WatchKit
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
draw
. Life was solitary, poor, nasty, brutish, and short.Rect:
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 |
---|---|
WKInterface |
UIView |
WKUser |
UIApplication + UIAlert
|
WKInterface |
UIDevice |
WKInterface |
UIView |
WKInterface |
UIButton |
WKInterface |
UILabel + NSDate
|
WKInterface |
UIScroll |
WKInterface |
UIImage |
WKInterface |
UILabel |
WKInterface |
MKMap |
WKInterface |
UITable / .separator
|
WKInterface |
UIStepper + UISlider
|
WKInterface |
UISwitch |
WKInterface |
UITable |
WKInterface |
UILabel + NSDate + NSTimer
|
As a namespace prefix,
WKInterface
sticks out like a sore thumb, butWK
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
WKInterface
manages the elements in a scene, whereas UIView
manages a view and its subviews. Interface objects are not views, but they act in similar ways.
The designated initializer for WKInterface
is init
, which accepts an optional context
object:
override init(context: Any Object?) {
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 UIView
s 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 managed
in the App Delegate.
But I digress.
Overall, WKInterface
’s API has a tiny footprint, and there’s no better illustration than its lifecycle methods:
// MARK: - WKInterface Controller
override func will Activate() {
…
}
override func did Deactivate() {
…
}
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 will
. Both during and after did
, 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 WKInterface
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 UIScroll
, 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 Watch Lists Interface Controller: WKInterface Controller, Lists Controller Delegate {
struct Watch Storyboard {
static let interface Controller Name = "Watch Lists Interface Controller"
struct Row Types {
static let list = "Watch Lists Interface Controller List Row Type"
static let no Lists = "Watch Lists Interface Controller No Lists Row Type"
}
struct Segues {
static let list Selection = "Watch Lists Interface Controller List Selection Segue"
}
}
…
}
WKInterfaceObject
WKInterface
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)do |
Switch | - (IBAction)do |
Slider | - (IBAction)do |
Table | - (IBAction)do |
Menu Item | - (IBAction)do |
For the small, closed set of controls, this approach is really appealing—much better than typing UIControl
.
WKInterfaceButton
WKInterface
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 UITap
.
WKInterfaceTable
Of all of the concepts carried over from iOS, tables are perhaps the most-changed.
UITable
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. WKInterface
, 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 WKInterface
, with each row specifying its own row controller (an NSObject
subclass with IBOutlet
s). WKInterface
can respond to table interactions either with the table:did
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, WKInterface
is perhaps the least-changed thing carried over from iOS. With support for NSAttributed
, 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: WKInterface
& WKInterface
.
WKInterface
is a special kind of label that displays the current date or time. WKInterface
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 NSDate
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, +
/ -
.
WKInterface
& WKInterface
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.