1

我希望我的复杂功能通过 Watch Connectivity 从 iPhone 获取数据。我正在使用sendMessage即时通讯技术。

当我尝试获取数据时,我不希望我的 iPhone 应用程序打开,因此这需要在后台运行。

在我 iPhone 上的 ViewController 中:

import UIKit
import WatchConnectivity

class ViewController: UIViewController, WCSessionDelegate {

var session: WCSession!

override func viewDidLoad() {
    super.viewDidLoad()
    if WCSession.isSupported() {
        self.session = WCSession.defaultSession()
        self.session.delegate = self
        self.session.activateSession()
    }
}

func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
    if message.count != 1 { return }

    if message["request"] != nil {
        replyHandler(["response" : "data"])
    }
}

在我的 ComplicationController

var session: WCSession!

func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: ((CLKComplicationTimelineEntry?) -> Void)) {
    if complication.family != .ModularSmall {
        handler(nil)
    }

    if WCSession.isSupported() {
        self.session = WCSession.defaultSession()
        self.session.delegate = self
        self.session.activateSession()
    }

    var respondedString = "not"

    session.sendMessage(["request" : ""], replyHandler: {
        (resp) -> Void in
        respondedString = resp["response"]
    }, errorHandler: nil)

    let circularTemplate = CLKComplicationTemplateModularSmallSimpleText()
    circularTemplate.textProvider = CLKSimpleTextProvider(text: respondedString)
    let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(), complicationTemplate: circularTemplate)
    handler(timelineEntry)
}

我在手表上唯一能看到的是“不是”。为什么并发症不显示接收到的数据?

4

1 回答 1

8

主要问题是您试图在复杂控制器中进行异步调用。

您调用之后的代码sendMessage:将在您的回复处理程序甚至得到响应之前执行。这就是为什么在您收到回复之前,由于模板的文本已设置,您的并发症显示“不是”。

稍后,在getCurrentTimelineEntryForComplication返回之后,sendMessage将收到响应并调用响应处理程序,该处理程序将仅设置respondedString,然后退出该块。

你应该避免做的事情:

您应该考虑Apple 的建议,不要尝试在复杂控制器中获取任何数据。

数据源类的工作是尽快为 ClockKit 提供任何请求的数据。您的数据源方法的实现应该是最少的。不要使用您的数据源方法从网络中获取数据、计算值或执行任何可能延迟该数据交付的事情。如果您需要为您的复杂功能获取或计算数据,请在您的 iOS 应用程序或您的 WatchKit 扩展的其他部分中执行此操作,并将数据缓存在您的复杂数据源可以访问它的位置。您的数据源方法唯一应该做的就是获取缓存的数据并将其放入 ClockKit 所需的格式。

此外,您在数据源中执行的任何活动都将不必要地耗尽分配给您的并发症的每日执行时间预算。

您如何为您的并发症提供数据?

Apple 提供了一种 Watch ConnectivitytransferCurrentComplicationUserInfo方法,该方法将立即将复杂信息(字典)从手机传输到手表。

当您的 iOS 应用收到针对您的复杂功能的更新数据时,它可以使用 Watch Connectivity 框架立即更新您的复杂功能。WCSession 的 transferCurrentComplicationUserInfo: 方法向您的 WatchKit 扩展发送高优先级消息,根据需要唤醒它以传递数据。收到数据后,根据需要扩展或重新加载您的时间线,以强制 ClockKit 从您的数据源请求新数据。

在手表方面,您WCSessionDelegate掌握didReceiveUserInfo并使用收到的数据来更新您的并发症:

func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) {
    if let ... { // Retrieve values from dictionary

        // Update complication
        let complicationServer = CLKComplicationServer.sharedInstance()
        guard let activeComplications = complicationServer.activeComplications else { // watchOS 2.2
            return
        }

        for complication in activeComplications {
            complicationServer.reloadTimelineForComplication(complication)
        }
    }
}

Apple 工程师通常建议设置数据管理器来保存数据。在您的并发症控制器中,您将从数据管理器中检索最新信息以用于您的时间线。

GitHub 上有几个使用这种方法的现有项目。

如果您仍然喜欢从手表端请求数据:

您希望将WCSession代码从复杂控制器中移出到手表扩展中,并将其作为WKExtensioninit 的一部分激活。

关键是让回复处理程序在收到数据后手动更新并发症。

当您的会话委托的回复处理程序被调用时,您可以使用我之前提供的更新并发症代码来重新加载您的并发症的时间线。

如果您使用计划的复杂功能更新来触发此操作,那么该特定方法的缺点是您将执行两次更新。第一次更新将启动数据请求,但没有任何新数据可供使用。第二次(手动)更新发生在收到数据之后,此时新数据将出现在时间线上。

这就是为什么从手机在后台提供数据的方法效果更好的原因,因为它只需要一次更新。

于 2016-04-26T07:01:45.740 回答