Watchkit — didReceiveApplicationContext работает только в первый раз

Когда я запускаю приложение для подключения часов с симуляторами iOS и watchOS в Xcode, метод делегата WCSession didReceiveApplicationContext работает только в первый раз, но затем он не вызывается, и в контроллере интерфейса ничего не меняется. Может ли кто-нибудь объяснить причину, почему это происходит?

Ниже представлен класс WCSessionVC UIViewController.

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

Ниже представлен класс InterfaceController класса WKInterfaceController.

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

person iAnkit    schedule 26.06.2018    source источник


Ответы (1)


Причина этого в том, что updateApplicationContext срабатывает только при изменении содержимого словаря контекста приложения. документация Apple описывает это как (выделено мной):

Используйте метод updateApplicationContext(_:) для передачи последней информации о состоянии контрагенту. Когда партнер просыпается, он может использовать эту информацию для обновления своего состояния. Например, приложение iOS, поддерживающее фоновое обновление приложения, может использовать часть времени фонового выполнения для обновления соответствующего приложения Watch. Этот метод перезаписывает предыдущий словарь данных, поэтому используйте этот метод, когда вашему приложению нужны только самые последние значения данных.

Так что думайте об этом как о методе установки свойств, который запускает KVO только тогда, когда значение действительно изменяется. Здесь метод делегата принимающей стороны запускается только при изменении содержимого словаря, поэтому в приведенном выше примере, если вы измените эту строку:

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

быть таким:

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

Вы увидите, что делегат принимающей стороны каждый раз получает обратный вызов.

person ccjensen    schedule 30.06.2018
comment
спасибо @ccjensen, я боролся с этой проблемой с утра. понял проблему. большое спасибо. - person CKT; 24.05.2021