I want my complication to get data from the iPhone via Watch Connectivity. I am using sendMessage
Instant Messaging technology.
I don't want my iPhone app to be open when I try to get data, so this needs to work in the background.
In my ViewController on my 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"])
}
}
And in my 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)
}
The only thing I can see on my Watch is "not". Why doesn't the complication show the received data?
The main issue is that you're trying to make an asynchronous call within your complication controller.
The code following your
sendMessage:
call will be executed before your reply handler has even gotten a response. This is why your complication shows "not" as the template's text has been set, before you have received a reply.Sometime later, after
getCurrentTimelineEntryForComplication
has returned,sendMessage
will receive a response and call the reply hander, which will merely setrespondedString
, then exit that block.What you should avoid doing:
You should consider Apple's recommendations, and not try to fetch any data within the complication controller.
Also, any activity you perform within your data source will needlessly use up the daily execution time budget that is allotted to your complication.
How can you provide data to your complication?
Apple provides a Watch Connectivity
transferCurrentComplicationUserInfo
method which will immediately transfer (a dictionary of) complication info from the phone to the watch.On the watch side, you have your
WCSessionDelegate
handledidReceiveUserInfo
and use the data you received to update your complication:Apple engineers generally recommend setting up a data manager to hold the data. In your complication controller, you would retrieve the latest information from the data manager to use for your timeline.
There are several existing projects on GitHub which use this approach.
If you still prefer to request data from the watch side:
You'd want to move your
WCSession
code out of the complication controller, into the watch extension, and activate it as part of theWKExtension
init.The key is to have the reply handler manually update the complication once the data is received.
When your session delegate's reply handler is called, you can use the update complication code I supplied earlier to reload your complication's timeline.
If you use scheduled complication updates to trigger this, the downside to that particular approach is that you'll be performing two updates. The first update would initiate the request for data, but not have any new data to use. The second (manual) update happens after the data is received, and this is when the new data would appear on the timeline.
This is why the approach of supplying data in the background from the phone works better, as it only requires one update.