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