WatchConnectivity 通过在 iphone 上启动计时器发送手表消息

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

我创建了一个在 iphone 上运行的计时器应用程序。 我希望我们可以控制它 iPhone 和 Watch

iPhone 的控件(播放、停止、重启)工作正常,我的仪表显示在手表上。

Watch on the Stop 效果很好,因为在 Start 上不起作用,仪表不亮 iPhone 或 Watch。

也重新开始工作。

如果信息来自 Watch,我在 iPhone 上的标签更改起来非常缓慢,但在另一个方向上效果很好,朝向 iPhone Watch

你注意到这个问题了吗,是WatchConnectivity相关的问题

感谢您的帮助

下面是我的代码:

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)")
        })

    }

}

}


你应该使用这个:

   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"
    }
}


我无法解释为什么我们需要显式使用 NSRunLoop。在开发具有数据传输功能的应用程序时,我遇到了同样的计时器问题。您可以通过查询 "nstimer run loop" 或 here 在 google 中找到一些答案。
我更喜欢用它来重启:

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


干杯。

此功能和优化代码:

//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"
        }
    }
}