Rewriting Nearly Departed (Part 4: Storage and Sync)

This post gives an overview about how Nearly Departed Routes are stored and synced between iPhone and Apple Watch.

This is part 4 of a multi-part series:

Route storage

Routes are stored in UserDefaults on the iPhone, and shared with the Watch using WatchConnectivity. To keep things simple, I have a Storing protocol for storing preferences and two implementations - one for the iPhone and one for the Watch.

The iPhone implementation stores preferences in UserDefaults and also sends things to the Watch. The Watch implementation simply talks to its counterpart on the iPhone.

After some experimentation (and help from Apple’s WatchConnectivity documentation and Kristina Fox’s blog), I settled on this communication strategy:

  • When the Watch app first starts, it requests the current preferences by sending a “get” command to the iPhone via Interactive Messaging:

    1
    2
    3
    4
    5
    
      session.sendMessage(["cmd" : "get"], replyHandler: { (reply) in
        // handle reply from phone
      }) { (error) in
        // handle error
      }
    

  • If preferences change on the iPhone, it sends data to the Watch by updating the Application Context:

    1
    2
    
      // prefs is [String : Any]
      session.updateApplicationContext(prefs)
    

  • If preferences change on the Watch, it sends data to the iPhone using Interactive Messaging:

    1
    2
    3
    4
    
      // prefs is [String : Any]
      session.sendMessage(prefs, replyHandler: nil, errorHandler: { (error) in
        // handle error
      })
    

This strategy seems to work well; both Application Context and Interactive Messaging work reliably, and quickly. (I’m testing with iOS 11.2 and WatchOS 4.2)

Phone dependence

This means that the Watch app doesn’t store any preferences locally, but instead gets preferences from the iPhone every time the Watch app starts. This is fine for now, but will be a problem when cellular Watches are more common. I’ll make a change in the future to store preferences locally on the Watch, so the app can start without a nearby phone.