Watchkit - didReceiveApplicationContext 仅在第一次工作

Watchkit - didReceiveApplicationContext works only for the first time

当我 运行 带有 iOS 的手表连接应用程序和 Xcode 中的 watchOS 模拟器时,WCSession 委托方法 didReceiveApplicationContext 仅适用于第一次,但随后它没有被调用,并且界面控制器中没有任何变化。谁能解释一下为什么会这样?

下面是UIViewController

的WCSessionVCclass
import Foundation
import UIKit
import WatchConnectivity

class WCSessionVC: UIViewController, WCSessionDelegate {

    let session = WCSession.default

    override func viewDidLoad() {
        super.viewDidLoad()

        session.delegate = self
        session.activate()
    }

    func updateApplicationContext(applicationContext: [String : Any]) throws {
        if WCSession.default.isPaired {
            do {
                try WCSession.default.updateApplicationContext(applicationContext)
            } catch let error {
                throw error
            }
        }
    }

    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        print("Session activated")
        let message = ["quote": "Hello"]
        do {
            try self.updateApplicationContext(applicationContext: message as [String : Any])
        }
        catch {
            print(error)
        }
    }
}

下面是WKInterfaceController

的InterfaceControllerclass
import WatchKit
import Foundation
import WatchConnectivity

class InterfaceController: WKInterfaceController, WCSessionDelegate {

    @IBOutlet var lblUserId: WKInterfaceLabel!

    var watchSession: WCSession? {
        didSet {
            if let session = watchSession {
                session.delegate = self
                session.activate()
            }
        }
    }

    override func awake(withContext context: Any?) {
        super.awake(withContext: context)

        if let session = watchSession {
            session.delegate = self
            session.activate()
        }
        // Configure interface objects here.
    }

    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()
        //loadDataFromDatastore()
        watchSession = WCSession.default
    }

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

    //MARK: Delegate Methods
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        watchSession?.activate()
        print("Session activation did complete")
    }

    func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
        DispatchQueue.main.async {
            print("watch received app context: ", applicationContext)
            if let data = applicationContext["quote"] as? String {
                self.lblUserId.setText(data)
            }
        }
    }

    func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
        print(message)
    }
}

之所以这样,是因为updateApplicationContext只有在应用程序上下文字典的内容发生变化时才会触发。 apple documentation 将其描述为(重点是我的):

Use the updateApplicationContext(_:) method to communicate recent state information to the counterpart. When the counterpart wakes, it can use this information to update its own state. For example, an iOS app that supports Background App Refresh can use part of its background execution time to update the corresponding Watch app. This method overwrites the previous data dictionary, so use this method when your app needs only the most recent data values.

所以把它想象成一个属性setter方法,只有当值实际改变时才会触发KVO。这里接收方委托方法仅在字典内容更改时触发,因此在上面的示例中,如果更改此行:

let message = ["quote": "Hello"]

变成这样:

let message = ["quote": "Hello", "date": NSDate()]

您会看到接收方委托每次都会收到回调。