0

当我在 Xcode 中使用 iOS 和 watchOS 模拟器运行手表连接应用程序时,WCSession 委托方法 didReceiveApplicationContext在第一次工作,但随后它没有被调用,并且接口控制器中没有任何变化。谁能解释一下为什么会发生这种情况?

下面是 UIViewController 的 WCSessionVC 类

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 的 InterfaceController 类

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

1 回答 1

6

这样做的原因是因为updateApplicationContext仅在应用程序上下文字典的内容发生变化时触发。苹果文档将其描述为(重点是我的):

使用 updateApplicationContext(_:) 方法将最近的状态信息传达给对方。当对方醒来时,它可以使用此信息来更新自己的状态。例如,支持Background App Refresh 的iOS 应用可以使用其部分后台执行时间来更新对应的Watch 应用。此方法会覆盖之前的数据字典,因此当您的应用仅需要最新数据值时使用此方法

所以把它想象成一个属性设置器方法,它只在值实际发生变化时才触发 KVO。此处接收方委托方法仅在字典内容更改时触发,因此在上面的示例中,如果您更改此行:

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

变成这样:

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

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

于 2018-06-30T10:21:40.343 回答