I'm trying to make a watchOS 3 app, and I want to update my complication in a background task.
First, I get new data from a server in a background task within handle()
. After that, I update my active complications by calling complicationServer.reloadTimeline(for:)
.
In the console I do see the message "UPDATE COMPLICATION," so the code is executed.
Yet after reloading, the complication still shows the old data. If I switch the watch face and switch back, then the complication sometimes reloads. Do I have to do something else to reload the complication from the background task?
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
for task : WKRefreshBackgroundTask in backgroundTasks {
if (WKExtension.shared().applicationState == .background) {
if task is WKApplicationRefreshBackgroundTask {
let dataProvider = DataProvider()
dataProvider.getData(station: "Name", completion: { (data, error) in
self.updateComplication()
self.scheduleNextBackgroundRefresh()
task.setTaskCompleted()
})
}
} else {
task.setTaskCompleted()
}
}
}
func updateComplication() {
let complicationServer = CLKComplicationServer.sharedInstance()
for complication in complicationServer.activeComplications! {
print("UPDATE COMPLICATION")
complicationServer.reloadTimeline(for: complication)
}
}
Your current approach:
You've got a mix of watchOS 2 and watchOS 3 approaches there.
In short, you've expected your background refresh task to wait in the background for an asynchronous transfer. This is bit convoluted (since the refresh task is supposed to be doing work in the background, not waiting on other work to complete).
A better way for watchOS 3:
Since an asynchronous transfer can be suspended, you would be better off using a
URLSession
background transfer.By letting a
WKURLSessionRefreshBackgroundTask
respond to the background transfer, your extension can be woken in the background once the session completes, hand off that session's data to the data provider, and then update the complication.An suggestion about the data provider:
It seems to have the responsibility of both transferring data, and providing data. You may want to consider splitting off the network portion into a separate component, and simply let it be a repository of data.
I get the impression that it's meant to be some manner of singleton (behind the scenes) yet you initialize an instance as a
DataProvider()
.From a readability viewpoint, it's not apparent from the provided code that the complication data source will be using the same data provider as the one who received the data.
You should avoid force unwrapping optionals:
When
activeComplications
is nil (such as when the complication had been removed from the watch face between the last update and this update), your code will ungraciously crash.You should use a
guard
orif let
to first check that you still have an active complication.