Background data transfers via User Info should be done when you need to make sure that all your data is transferred (not just the latest like with Application Context). User Info data is queued up for delivery in a FIFO (first-in-first-out) order, so nothing is overwritten.
One examples for when you might want to use this is in a text messaging app – when the last message is just as important as the first to see the full conversation and context. Or if the user updated a few pieces of their profile information and all the changes need to be synced to the Watch profile.
For this tutorial, I’m going to walk through building a food emoji communication app because food and emoji! I LOVE 🍦!
Also, this could potentially be an Apple Watch based grocery list app – you select the food you plan to buy from the list of emojis on the phone, and it goes to the app, which you can then glance at as you shop at the grocery store!
Note that for this app, I’m going to write more of an abstract data updating layer meant for larger applications with multiple places in the UI that need to have the updated data source, so it’ll be over-engineered for the app I’m demoing.
I’m also experimenting with different architectures, especially in Swift, so if you have feedback on how to make the abstract data layer better in Swift, let me know in the comments!
For this tutorial, I’m assuming you know how to create a Single View Application in Xcode, and create a simple Table View with a list of Food Emojis. If you’re having problems replicating it, take a look at my FoodSelectionViewController here.
I’m also assuming you know how to create a Watch App and do the basic styling in Interface.storyboard of your Watch Application. If you need help settings this up, make sure to read my WatchOS 2: Hello, World tutorial and the WatchKit: Let’s Create a Table tutorial.
Finally, you should be able to set up the basic singleton to wrap around WCSession and activate it in application:didFinishLaunchingWithOptions in the AppDelegate and applicationDidFinishLaunching in the ExtensionDelegate in your Watch Extension. If not, take a look at my WatchConnectivity: Say Hello to WCSession tutorial.
And of course, you can always refer to the source code for this tutorial if you ever need extra clarification.
Now, on to the fun stuff 🚀.
In my application, every time the user selects a food item, it needs to be transferred in the background to my Watch App. That means the iOS app is the sender. This is super simple to do.
That’s it! The selected food item is now in a FIFO queue and will be send over to your Watch App!
Your Watch App now has to receive the data. This is pretty simple to start with. Just implement the session:didReceiveUserInfo: WCSessionDelegate method.
Now that you received the data, this is the tricky part. Trying to let your Watch Extension’s InterfaceController and other views or data sources that your data has been updated. One way to do this is through NSNotificationCenter, but I’m going to try out a different approach. This is the part that can be done in multiple ways and is a bit over-engineered for this app, so keep this in mind.
Since we’re in Swift, my goal is to change to a value-type model as soon as I can. Unfortunately, as I mentioned in my blog post on WCSession, the WCSessionDelegate can only be implemented on an NSObject. So to mitigate that, I created a DataSource value that can take the userInfo data, and convert it into something immutable and usable by multiple InterfaceControllers. Since user info is received in a FIFO queue order, the DataSource should also keep track of the data in the order received.
Now, we just need to make sure our InterfaceController is DataSourceChangedDelegate, and is kept track of by the WatchSessionManager.
// update the table once the data is changed!
You can view the full source code on Github here.