The online home of John Pollard

Synching user settings on watchOS 2

In my last post I mentioned that watchOS 2 doesn’t have access to NSUserSettings, which isn’t entirely correct. The watch can have access to user settings, it’s just it can’t directly synchronise them when they are backed by iCloud.

This means if we change the user settings on the phone we need to push the changes to the watch ourselves.

This isn’t too tricky to do if you follow the instructions on the Apple Developer site about using WCSession to set up a sharing session between the phone app and your watch extension.

As I wanted to continue sharing code between the two apps, I’ve had to add a slightly hacky onWatch property to the settings class so it:

  • Only uses iCloud synchronisation on the phone
  • If a setting is changed on the phone, it sets up a WCSession and uses it to send a Dictionary containing the changes via transferUserInfo()
  • The watch will receive those changes in didReceiveUserInfo() which it can then use to update it’s local settings

There’s a small “code smell” of adding in this onWatch flag just so I can reuse some code in this way, so I may come back and revisit this code later.

According to the docs transferUserInfo() queues any transfers up to send to the watch when a connection is available.

The solution seems to work pretty well - in the watch simulator at least! On the watch itself the app does seem to run rather slow, but TBH that seems a problem with most watchOS apps I’ve used. More investigation needed!

Next steps: Start tidying up the UI in the existing app, and see if we can improve the performance on the actual watch.

N.B. All code can be seen on GitHub

Updating code to watchOS 2

Updating my Count The Days Left app to watchOS 2 is clearly going to be more work than I thought :(

Upgrading to latest version of Swift

After loading the existing project into Xcode 7, it prompted me to update the Swift code, and when I accepted did a pretty good job of fixing everything up.

As a learning experience I reverted the changes to fix them up myself. Changes made included:

  • Changing the way string length is calculated e.g. count(self.model.title) => self.model.title.characters.count
  • Using generic Dictionary<String, AnyObject> where previous used NSDictionary
  • Updating NSCalendarUnit values e.g. NSCalendarUnit.CalendarUnitDay to NSCalendarUnit.Day
  • touchesBegan() event handler now has a Set<UITouch> parameter instead of a Set<NSObject> (and a ? on the event)
  • Lots of places I’d used var could be replaced by let - too much C# in the day job I suspect :)

Two versions of the shared library required

The big architecture change in watchOS 2 is that the watch extension code runs on the watch not the phone.

This should make the app much quicker, but brings in a whole raft of problems when migrating the code.

First up was making use of the shared library on code used by both the iOS app and the extension. The version running on the watch needs to be compiled against the watchOS SDK (obviously).

Getting this working stumped me for a while until I found this transition guide on the Apple developer site. See the Sharing Code Between an iOS App and a watchOS App section on how to make a duplicate library using the same files but compiling against the correct SDK.

Can’t share NSUserSettings any more

After solving the above problems, everything built and deployed to the simulator/phone/watch OK, but the watch app didn’t actually work. However a bit more reading of the upgrading code documentation pointed out a fundamental problem.

Because the extension has moved over to the watch, it doesn’t have access to the NSUserSettings objects, even if we’ve set up the App Groups capability correctly.

This means I’ll have to roll my own sharing of data between the app and the extension, which is a bit of a pain, but should be fun to learn.

More on how I get on next time!

N.B. All code can be seen on GitHub

WatchOS Development Phase 2

So I treated myself of an Apple Watch.

I’m enjoying it so far, but despite being heads down in getting the all-new v3.0 of Daily Optimiser out the door, and back contracting in London (earning some money!), I wanted to make some improvements to Count The Days Left now I can actually see it running on an actual watch.

There are several things in the original version that can be improved on or added to. In no particular order:

  • Upgrade to watchOS 2 and latest version of an ever evolving Swift
  • Design! A white background? What was I thinking :(
  • Adding a glance. It’s now pretty obvious this is the natural place for main access to the app (like the Today widget is the most useful part of the main iOS app)
  • Adding a complication so the days left can be seen on the main watch screen

I’m hoping to get all the above done quite quickly, and as before I’ll be blogging here about what I do as well as sharing the code on GitHub

If you missed it and you’re interested, you can see a summary of the previous iteration , which includes links to earlier posts.

What I Didn't Know When I Was Young

I’ve just finished a significant rewrite of our Daily Optimiser app - hopefully in the App Store soon assuming it gets through the review process.

This was the first iOS app I wrote, and going back to the code after 12 months or so further learning it’s clear I’ve learnt a lot about mobile design and development during that time!

The code itself was actually pretty reasonable. Other than some improvements to the threading and callback model, there weren’t so many fundamentals I had to change. However as a non-designer I think my understanding of what makes a well designed app is what’s changed the most.

Some fairly obvious (now!) observations on what I’ve tried to do in v2.0:

  • More important screen elements should be larger and use more screen real-estate
  • Stick to a small and consistent color palette
  • A few small subtle animations can make a big difference
  • Stick to standard design patterns and elements as much as possible

I think Daily Optimiser v2.0 is a big improvement on the first version - hopefully our users will agree!

App Development using Swift - A Summary

My first app written in Swift has now shipped and with the Apple Watch update now live too I think we can call it done.

So what did I learn?

Swift - good and bad

The Swift language itself is pretty well designed, and a LOT easier on the eye than Objective-C. The syntax is pretty similar to many modern languages and I think I became reasonably productive quite quickly.

The only downside is that most of the code I wrote was generally just interacting with the iOS frameworks, which aren’t particularly Swift-friendly right now. This means you spend a lot of time dealing with nullable pointers, and with all the slightly mysterious ?s, the code loses some of the readability gains.

Hopefully this will get better over time, any maybe this year’s WWDC will see some progress in making the frameworks a little more Swift-friendly? Let’s hope so.

Summary

I enjoyed using Swift, and almost certainly for any new apps starting from scratch I’ll use it.

However I don’t see there is enough - or any - real advantage in porting any existing Objective-C code so any existing apps that I’m working on I think I’ll keep that way.

Anyway, I learnt a lot and I hope you enjoyed following along!

Previous posts in the series

The code for the project is also available on GitHub