Watch​Kit

Written by Mattt Thompson

Everyone is excited about ᴡᴀᴛᴄʜ. Developers especially.

What’s the best way to get started? Look no further than Apple’s WatchKit developer resources.

  • Watch the “Getting Started” video—it’s like being in Moscone.
  • Read the Human Interface Guidelines—consider it a prerequisite for designing your application.
  • Peruse the WatchKit Programming Guide and WKInterfaceCatalog for an introduction everything the framework provides.
  • And when you’re finally ready to add that App Extension target to your app, consult the Lister Sample App (in both Objective-C & Swift!) to see how everything fits together.

Apple’s Developer Publications, Developer Evangelism, and WatchKit teams knocked it out of the park with the WatchKit launch. The official resources are superb.

That said, after taking a look at everything, there were a few things that jumped out as it relates to UIKit. They’re the kind of subjective, opinionated things that don’t make for good documentation, but might be interesting or useful to anyone else as they’re getting started.

So this week, some initial impressions of WatchKit from the perspective of an iOS developer.


WatchKit harkens back to the earliest days of iOS development, when the platform limitations acted as liberating constraints for developers. Compared to OS X & AppKit, mired in decades of cruft and churn, iPhoneOS (as it was originally known) & UIKit were a breath of fresh air. Apps were small, simple, and humble.

After 7 years and as many major releases, iOS has grown to encompass myriad devices and configurations, from iPhones and iPads of all shapes and sizes, to the TV and CarPlay. It’s still an amazing developer experience (for the most part), but it feels like some of the magic has been lost along the way.

Counterpoint: Nostalgia is bullshit. Remember, back in those days, there was no ARC, no GCD, no Interface Builder support for iOS and certainly no Swift. The indispensable open source libraries of the time were Three20 and asi-http-request. The state of the art for table view scroll performance was to manually composite text and images in a cell’s content view drawRect:. Life was solitary, poor, nasty, brutish, and short.

Regardless of where you’re personally coming from, the simplicity of WatchKit is something to be enjoyed and celebrated.

Comparison to UIKit

WatchKit bears a striking resemblance to UIKit, which is not entirely surprising, given their shared history and purpose. Watches are different from phones and tablets, which themselves are different from desktops. Some concepts are shared, but each have unique purposes and constraints that shape the topography of their software.

For sake of comparison, here is how one might understand WatchKit in terms of UIKit / Cocoa concepts:

WatchKit UIKit
WKInterfaceController UIViewController
WKUserNotificationInterfaceController UIApplicationDelegate + UIAlertController
WKInterfaceDevice UIDevice
WKInterfaceObject UIView
WKInterfaceButton UIButton
WKInterfaceDate UILabel + NSDateFormatter
WKInterfaceGroup UIScrollView
WKInterfaceImage UIImageView
WKInterfaceLabel UILabel
WKInterfaceMap MKMapView
WKInterfaceSeparator UITableView.separatorColor / .separatorStyle
WKInterfaceSlider UIStepper + UISlider
WKInterfaceSwitch UISwitch
WKInterfaceTable UITableView
WKInterfaceTimer UILabel + NSDateFormatter + NSTimer

As a namespace prefix, WKInterface sticks out like a sore thumb, but WK on its own was recently claimed by the new WebKit framework. Although the Watch platform is a long way from being able to embed web views, the decision to demarcate things as they are is sensible.

There’s a lot of overlap, but there are important differences. Understanding those differences is both informative to making great WatchKit apps as well as enlightening in terms of how Apple’s thinking about API and best practices continues to evolve.

WKInterfaceController

WKInterfaceController manages the elements in a scene, whereas UIViewController manages a view and its subviews. Interface objects are not views, but they act in similar ways.

The designated initializer for WKInterfaceController is initWithContext:, which accepts an optional context object:

override init(context: AnyObject?) {
    super.init(context: context)

    // ...
}

What’s a context? It’s anything you want it to be: a date, a string, a model object, or nothing at all.

The open-endedness of context may be disorienting at first, but it’s actually a remarkably clever solution to a long-standing problem of UIKit—namely, the difficulty passing information between view controllers. Without a standard convention for configuring UIViewControllers as they are pushed, popped, and presented, developers are regularly faced with a miserable choice between custom designated initializers (incompatible with Storyboards), property configuration (prone to creating controllers with incomplete state), custom delegates (overly ceremonious when done correctly), or notifications (just… no). It’s for this reason that so many applications backed by Core Data fall into the pattern of referencing a shared managedObjectContext in the App Delegate.

But I digress.

Overall, WKInterfaceController’s API has a tiny footprint, and there’s no better illustration than its lifecycle methods:

// MARK: - WKInterfaceController

override func willActivate() {
    // ...
}

override func didDeactivate() {
    // ...
}

That’s it: 2 methods. No loading / unloading, no will / did appear / disappear, no animated:YES. Watch apps are simple by necessity. Communication between the iOS device driving the application and the watch is both time-consuming and battery-consuming, so all of the setup for the interface controller’s scene is to be done in the initializer and willActivate. Both during and after didDeactivate, the Watch will ignore attempts to update the state of interface elements.

Watch applications are either Hierarchical or Page-Based. This is similar to Xcode’s project templates for “Master-Detail Application”, “Page-Based Application”, and “Tabbed Application”, except that the design choices are mutually exclusive.

Hierarchical applications have an implicit navigational stack, which WKInterfaceController can manage with -pushControllerWithName:context: & -popController. One thing to note here is how -pushControllerWithName:context: takes a string—the name of the controller as specified in the Storyboard—rather than an instance of the controller itself.

Page-Based applications, on the other hand, act like a horizontal or vertical paged UIScrollView, with a pre-determined number of scenes each managed by a controller. It will be interesting to see which use cases are best served by Page-Based and Hierarchical interfaces. Without trying out stock applications on a real device, there’s not much context to understand the trade-offs of each intuitively.

As a final aside, there is an interesting pattern in Apple’s Swift sample code, to use inner structs as namespaces for Storyboard constants:

class WatchListsInterfaceController: WKInterfaceController, ListsControllerDelegate {
    struct WatchStoryboard {
        static let interfaceControllerName = "WatchListsInterfaceController"

        struct RowTypes {
            static let list = "WatchListsInterfaceControllerListRowType"
            static let noLists = "WatchListsInterfaceControllerNoListsRowType"
        }

        struct Segues {
            static let listSelection = "WatchListsInterfaceControllerListSelectionSegue"
        }
    }

    // ...
}

WKInterfaceObject

WKInterfaceObject resembles a streamlined rendition of UIView, with properties for alpha, hidden, horizontal & vertical alignment, and width & height.

The most striking difference is the lack of a frame. Instead of manually specifying coordinate points or setting up Auto Layout constraints, WatchKit interface objects are laid out in a grid according to their margins and respective ordering, which is reminiscent to working with a CSS framework like Bootstrap (or for you Rubyists out there, remember Shoes?).

Another departure from Cocoa Touch is that Target-Action methods use a fixed-format specific for each type of control, rather than passing a dynamic sender and UIEvent.

Object Action Method
Button - (IBAction)doButtonAction
Switch - (IBAction)doSwitchAction:(BOOL)on
Slider - (IBAction)doSliderAction:(float)value
Table - (IBAction)doTableRowTapAction:(NSInteger)rowIndex
Menu Item - (IBAction)doMenuItemAction

For the small, closed set of controls, this approach is really appealing—much better than typing UIControlEventTouchUpInside.

WKInterfaceButton

WKInterfaceButton is an interface object that can be tapped to trigger an action. Its contents can be either a single text label or a group.

That latter part—being able to contain a group—is huge. This avoids one of the biggest gripes folks have with UIButton, the difficulty of adding subviews and having things position and interact correctly, which would otherwise drive people to give up and use UITapGestureRecognizer.

WKInterfaceTable

Of all of the concepts carried over from iOS, tables are perhaps the most-changed.

UITableView is the backbone of iPhone applications. As such, they’ve evolved significant complexity to handle the demands of applications with a lot of data that needs to be displayed in many different ways. WKInterfaceTable, by comparison, seems marginal by comparison.

WatchKit tables do not have sections or headers, or footers, or editing, or searching, or data sources, or delegates. Rows are pre-populated at WKInterfaceController -willActivate, with each row specifying its own row controller (an NSObject subclass with IBOutlets). WKInterfaceController can respond to table interactions either with the table:didSelectrowAtIndex: delegate method, or using the aforementioned Target-Action method.

It may not seem like much, but this approach is well-suited for the watch, and is a lot more straightforward than on iOS.

WKInterfaceLabel

By contrast, WKInterfaceLabel is perhaps the least-changed thing carried over from iOS. With support for NSAttributedString, custom fonts, and font scaling, it’s pretty much everything you could ask for.

WKInterfaceDate & WKInterfaceTimer

Let us not forget that time is a pretty important concept for watch. As such, WatchKit introduces two new interface objects that are unprecedented in Cocoa or Cocoa Touch: WKInterfaceDate & WKInterfaceTimer.

WKInterfaceDate is a special kind of label that displays the current date or time. WKInterfaceTimer is similar, except that it displays a countdown until a specified date.

Including these two classes does as much to ensure app quality as much as anything else in WatchKit. Given how these essential these tasks are for a watch, and how notoriously bad programmers are at using NSDateFormatter and NSTimer, one can only imagine where we’d be without these.

WKInterfaceSlider & WKInterfaceSwitch

Sliders and Switches are due for a comeback on the watch. Without the benefit of touch gestures, interfaces are resigned to go back to basics. Tap, Tap, On / Off. Tap, Tap, + / -.

WKInterfaceSlider & WKInterfaceSwitch both appear to be well-crafted and rather customizable.


This is, of course, but a superficial reflection into the capabilities of WatchKit. Like I said at the beginning of the article, Apple’s official resources for WatchKit have everything you could ever need.

NSMutableHipster

Questions? Corrections? Issues and pull requests are always welcome — NSHipster is made better by readers like you.

This article uses Swift version 1.0. Find status information for all articles on the status page.

Follow NSHipster
Next Article

There’s a unique brand of modern angst that manifests the moment you decide to buy something online. While there’s no English word for it, it translates roughly to “Where is my credit card? What is its number? How badly do I actually want this thing, anyway?”