0

我希望我的复杂功能通过Watch Connectivity从iPhone获取数据。我正在使用sendMessage即时消息传递技术。结合WatchConnectivity和复杂功能

我不希望iPhone应用程序在我尝试获取数据时打开,因此需要在后台工作。

在我的ViewController在我的iPhone:

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

我可以在我的收藏唯一看到的是 “不”。为什么复杂功能不显示接收到的数据?

+0

另外,您可能想在AppDelegate中设置iOS会话,而不是视图控制器。您总是希望尽快激活它(并使其在应用程序范围内可用)。 – 2016-04-26 07:30:23

回答

3

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

sendMessage:调用之后的代码将在之前执行您的答复处理程序甚至已得到响应。这就是为什么你的复杂功能在收到答复之前显示“不”,因为模板的文本已被设置。

过了一段时间,在getCurrentTimelineEntryForComplication已返回之后,sendMessage将收到回复并回复hander,该回复将仅设置respondedString,然后退出该块。

你应该避免做什么:

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

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

此外,您在数据源中执行的任何活动都会不必要地使用分配给复杂功能的每日执行时间预算。

如何为复杂功能提供数据?

Apple提供了一种手表连接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) 
     } 
    } 
} 

苹果的工程师通常建议设立一个数据管理器来保存数据。在您的复杂功能控制器中,您将从数据管理器中检索最新信息以用于您的时间线。

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

如果你还是喜欢从手表端请求数据:

你会想要移动WCSession码出复杂的控制器,融入腕表扩展,并激活它作为WKExtension的一部分在里面。

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

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

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

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

+0

另一个问题:我何时必须在iPhone应用程序中激活会话,以便它可以接收请求并发送响应。 viewDidLoad对我来说似乎不对,因为它不需要加载... – phipsG

+1

在AppDelegate中。如果应用程序在后台启动(当时已终止),则说明视图不会被加载。有关更多详细信息,请参阅[此答案](http://stackoverflow.com/a/33173625/4151918)。有些人建议设置一个'WCSession'管理器,而不是将所有委托代码放在'AppDelegate'中。无论如何,您应该尽可能早地启动iOS会话(这是应用程序启动的时间)。 – 2016-04-26 16:31:49

+0

复杂性的入口点实际上是什么,所以我可以在那里激活会话?就像在我的iOS应用中的didFinishLaunchingWithOptions – phipsG