简体   繁体   中英

WatchConnectivity send message of watch with the launch of a timer on the iphone

I created a timer app that runs on the iphone. I wish we could control it iPhone and Watch

Projet截图

The controls (Play, Stop, Restart) with the iPhone works fine, my meter is displayed on the Watch.

Watch on the Stop works well, for against the Start does not work, the meter does not turn on iPhone or the Watch.

Restart the works too.

My Label on the iPhone is very slow to change if the information comes from the Watch, but works well in the other direction, toward the iPhone Watch

Have you noticed this problem, it is a problem related to WatchConnectivity

Thanks for your help

Below is my code:

ViewController.swift

import UIKit
import WatchConnectivity

class ViewController: UIViewController, WCSessionDelegate {

@IBOutlet weak var timerLabel: UILabel!
@IBOutlet weak var watchLabel: UILabel!

var session: WCSession!
var timerCount = 0
var timerRunning = false
var timer = NSTimer()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    if (WCSession.isSupported()) {
        let session = WCSession.defaultSession()
        session.delegate = self
        session.activateSession()

        if session.paired != true {
            print("Apple Watch is not paired")
        }

        if session.watchAppInstalled != true {
            print("WatchKit app is not installed")
        }
    } else {
        print("WatchConnectivity is not supported on this device")
    }

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}    


@IBAction func startButton(sender: UIButton) {
    startPlay()
}

@IBAction func stopButton(sender: UIButton) {
    stopPlay()
}


@IBAction func restartButton(sender: UIButton) {
   restartPlay()
}

//Receive messages from watch
func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
    var replyValues = Dictionary<String, AnyObject>()

    //let viewController = self.window!.rootViewController as! ViewController      
    switch message["command"] as! String {
    case "start" :
        startPlay()
        replyValues["status"] = "Playing"
    case "stop" :
        stopPlay()
        replyValues["status"] = "Stopped"
    case "restart" :
        restartPlay()
        replyValues["status"] = "Stopped"
    default:
        break
    }
    replyHandler(replyValues)
}

//Counter Timer
func counting(timer:NSTimer) {
    self.timerCount++
    self.timerLabel.text = String(timerCount)

    let requestValues = ["timer" : String(timerCount)]
    let session = WCSession.defaultSession()
    session.sendMessage(requestValues, replyHandler: nil, errorHandler: { error in print("error: \(error)")})
}

//Fonction Play
func startPlay() {
    if timerRunning == false {
        self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("counting:"), userInfo: nil, repeats: true)
        self.timerRunning = true
        self.watchLabel.text = "START"
    }
}

//Fonction Stop
func stopPlay() {
    if timerRunning == true {
        self.timer.invalidate()
        self.timerRunning = false
        self.watchLabel.text = "STOP"
    }
}

//Fonction Restart
func restartPlay() {
    self.timerCount = 0
    self.timerLabel.text = "0";

    let requestValues = ["timer" : "0"]
    let session = WCSession.defaultSession()
    session.sendMessage(requestValues, replyHandler: nil, errorHandler: { error in print("error: \(error)")})
}
}

InterfaceController.swift

import WatchKit
import Foundation
import WatchConnectivity


class InterfaceController: WKInterfaceController, WCSessionDelegate {

@IBOutlet var watchLabel: WKInterfaceLabel!
@IBOutlet var statusLabel: WKInterfaceLabel!

//Receiving message from iphone
func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
    self.watchLabel.setText(message["timer"]! as? String)
    // self.statusLabel.setText(message["command"]! as? String)
}


override func awakeWithContext(context: AnyObject?) {
    super.awakeWithContext(context)
    // Configure interface objects here.
}

override func willActivate() {
    // This method is called when watch view controller is about to be visible to user
    super.willActivate()
    if (WCSession.isSupported()) {
        let session = WCSession.defaultSession()
        session.delegate = self
        session.activateSession()
    }
}

override func didDeactivate() {
    // This method is called when watch view controller is no longer visible
    super.didDeactivate()
}


@IBAction func startButtonWatch() {
    if WCSession.defaultSession().reachable == true {
        let requestValues = ["command" : "start"]
        let session = WCSession.defaultSession()
        session.sendMessage(requestValues, replyHandler: { reply in
            self.statusLabel.setText(reply["status"] as? String)
            }, errorHandler: { error in
                print("error: \(error)")
        })

    }

}


@IBAction func stopButtonWatch() {
    if WCSession.defaultSession().reachable == true {
        let requestValues = ["command" : "stop"]
        let session = WCSession.defaultSession()
        session.sendMessage(requestValues, replyHandler: { reply in
            self.statusLabel.setText(reply["status"] as? String)
            }, errorHandler: { error in
                print("error: \(error)")
        })

    }
}

@IBAction func restartButtonWatch() {
    if WCSession.defaultSession().reachable == true {
        let requestValues = ["command" : "restart"]
        let session = WCSession.defaultSession()
        session.sendMessage(requestValues, replyHandler: { reply in
            self.statusLabel.setText(reply["status"] as? String)
            }, errorHandler: { error in
                print("error: \(error)")
        })

    }

}

}


You should use this:

   func startPlay() {
    if timerRunning == false {
        //self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("counting:"), userInfo: nil, repeats: true)
        self.timer = NSTimer(timeInterval: 1, target: self, selector: "counting:", userInfo: nil, repeats: true)
        NSRunLoop.mainRunLoop().addTimer(self.timer, forMode: NSRunLoopCommonModes)
        self.timerRunning = true
        self.watchLabel.text = "Start"
    }
}


I cant explain you why we need use NSRunLoop explicitly. I stuck with same timer issue when develop an app with data transfer. Some answers you can find in google by query "nstimer run loop" or here .
And i pref use this for restart:

    func restartPlay() {
    self.timerCount = 0
    self.timerLabel.text = "0";
    stopPlay()
    startPlay()
    self.watchLabel.text = "Restarted"
}


Cheers.

This functional and optimized code :

//Fonction Play
func startPlay() {
    if timerRunning == false {
        self.mytimer = NSTimer(timeInterval: 1, target: self, selector: "counting:", userInfo: nil, repeats: true)
        NSRunLoop.mainRunLoop().addTimer(self.mytimer, forMode: NSRunLoopCommonModes)
        timerRunning = true
        dispatch_async(dispatch_get_main_queue()) {
            self.watchLabel.text = "PLAYING"
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM