I am trying to learn how to develop watchapps for the Apple Watch, and one thing seems a bit difficult to me: how's data supposed to be shared between the watchapp and the complication controller?
Most examples I see online follow the following order:
1 - download data on the ExtensionDelegate, and use it on the InterfaceController;
2 - get the ComplicationController to get the data from the ExtensionDelegate
3 - Add a background task on the ExtensionDelegate so that it downloads updated data that will be used by both the InterfaceController and ComplicationController, updating both.
So my data is in a collection at the ExtensionDelegate. I wonder:
1 - Who should initially get my ExtensionController to download the data when initiating the app? My ComplicationController or my InterfaceController? I ask this because on xcode there is a simulator for each of these, so sometimes I dunno which is called first when starting the app. Should the complication only start its life-cycle after an app is opened by the user, thus forcing a first data loading, or does it start after installing the app? Or should add a flag on the ExtensionDelegate to flag if there's no data downloaded, there's data being downloaded, there's data available (ie., collection is not null), so that either the ComplicationController or the InterfaceController can trigger a first data download?
2 - While my background download task works, I feel that over a few hours, my app has to be reloaded when opening, as if it wasn't opened before, thus triggering a new download of data. The data on it differs then from the data already downloaded and shown by the ComplicationController. What is a good strategy to tackle this? Any pointers on what I should be checking?
I am not sure if I understood your question right. Anyway, I do the data transfer from the iPhone to the watch in the following way:
Assume first that the iPhone app and the watch extension are installed, the iPhone app is not yet launched, but the watch extension is running in background, so that it can communicate with the iPhone as soon as the iPhone app runs.
Assume further, that the watch shows a watch face with a complication of the app.
When the iPhone app is launched, it sends first the complication data to the watch using
transferCurrentComplicationUserInfo(_:)
. So, the watch face shows the complication data.Subsequently the iPhone sends a message using
sendMessage(_:replyHandler:errorHandler:)
. This message tells the watch extension that the iPhone will send data soon. Since sending the data may take much longer, the initial message is used to display the hint loading data from the iPhone on the watch.Subsequently I send the data using
updateApplicationContext(_:)
.The 2nd scenario is that the iPhone app is running, but the watch extension not yet.
Now, as soon as the watch extension is launched, the
InterfaceController
usessendMessage(_:replyHandler:errorHandler:)
to send immediately a message to the iPhone that it requires data. When this message is received, the same sequence is executed as described above: The complication data are sent, the message is sent that data transfer will start soon, and the data transfer is initiated.This works without problems.
Regarding your questions:
In my case, the
InterfaceController
is initiating the transfer as soon as it is activated.However, when the watch extension is installed but not yet launched, my watch face shows already my (default) complication data. This means that the
ComplicationController
is actually running even if neither the watch extension nor the iPhone app are running. So it might be possible to start an initial data transfer this way.I did not have the problem that you mentioned in your 2nd question, so I cannot say anything to it.