结合WatchConnectivity和并发症

时间:2016-04-26 06:02:50

标签: swift watch-os-2 watchconnectivity apple-watch-complication wcsession

我希望我的复杂功能通过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)
}

我在手表上唯一能看到的是“不是”。为什么复杂性不能显示收到的数据?

1 个答案:

答案 0 :(得分:4)

主要问题是您正在尝试在并发症控制器中进行异步调用。

您的sendMessage:来电之后的代码将在回复处理程序获得响应之前执行。这就是为什么在收到回复之前,您的复杂功能会显示“未”,因为模板的文本已经设置。

稍后,getCurrentTimelineEntryForComplication返回后,sendMessage会收到回复并致电回复处理,这只会设置respondedString,然后退出该块。

你应该避免做什么:

您应该考虑Apple's recommendations,而不是尝试在并发症控制器中获取任何数据。

  

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

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

如何为并发症提供数据?

Apple提供了一种Watch Connectivity transferCurrentComplicationUserInfo方法,该方法将immediately从手机传输(词典)复杂信息到手表。

  

当您的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代码移出并发症控制器,进入监视扩展程序,并将其作为WKExtension初始化的一部分进行激活。

关键是让收件处理程序在收到数据后手动更新复杂功能。

调用会话委托的回复处理程序时,可以使用我之前提供的更新复杂代码重新加载复杂的时间轴。

如果您使用预定的并发症更新来触发此操作,那么该特定方法的缺点是您将执行两次更新。第一次更新将启动数据请求,但不会使用任何新数据。第二次(手动)更新在收到数据后发生,这是新数据出现在时间线上的时间。

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