I’m a long time Mac developer who started with Objective-C in 2000 on Mac OS X Public Beta (remember how slow that thing was!) and I’ve cut my teeth on numerous Mac projects. However, for the last couple years nearly all of my projects have been on iOS. So I was surprised when a recent project brought me back to the Mac and I discovered how finicky Cocoa really is. I was particularly shocked because I always remembered Cocoa as a particularly nice set of APIs. Where things are easy to do on iOS, making customizations can be rage inducing with Cocoa, especially when it comes to custom controls:
At first as a Mac developer, iOS was a little strange for me. I had to resist the urge to subclass and write custom drawing code for controls. On the Mac, to make a custom control you often subclass NSView and then write your own drawing code. Contrast this to iOS where custom controls are more often a combination of multiple views with images and CoreAnimation styles. A great example is how on iOS you have backgroundColor available on every view, in Cocoa there is no such thing. Instead you need to create a layer backed NSView (which has its own problem’s I’ll bring up later) or write custom drawing code.
Apple has embraced customization even further on iOS by providing a great set of APIs for styling the UI. For example, changing the navigation bar style on iOS is supported with a single API call. On the Mac if you want to customize the window title bar, you are going to be in for a world of pain. Apple provides no API for customizing things like the title bar on OS X. Instead, you have to subclass NSWindow and write your own custom drawing code. Getting this drawing code right requires much trial and error (like how do I add back in the close/minimize/expand buttons on the window) .
When customizing UI it’s often very useful to look at what others have done. iOS has tons of resources because of the pure number of developers, while the Mac has much much less. Much of the information on how to customize Cocoa controls isn’t documented. In fact when I was an intern at Apple long ago, when we had to customize Cocoa controls my boss would tell me to go lookup the source code for the control. I could then figure out which methods to override to get the proper style. However as an outside developer you don’t have access to these resources. On the iOS side there is a wealth of documentation just on Stack Overflow alone on how to customize and build UI.
The dreaded NSCell
I can’t talk about customizing UI in Cocoa and not bring up NSCell. iOS developers thankfully have no idea what I’m talking about.
Cocoa is an old framework, dating back to the early 90’s, consequently many aspects don’t make sense with current hardware. A perfect example is NSCell. In the 90’s it was a performance problem to have lots of NSView’s in a window at once. Since NSView’s were very resource intensive NSCell’s where intended to be used anywhere you would need lots of views. For example in a table view all the rows would be composed of NSCells instead of bloated NSViews. The NSCells had much less data and knew just how to stamp out the necessary content for the rows. In practice this becomes a problem because you then can’t add any control like a button to a table view, it has to be a NSCell.
iOS (thankfully) did away with this, as it is no longer a performance problem with our modern devices. However this vestige is still hanging around in Cocoa, complicating all our custom controls. Everytime you want to customize something you need to create both a custom view and custom cell. This doesn’t sound too bad, but after you’ve been spoiled by iOS you get frustrated quickly.
In fairness, Apple is improving this. They’ve introduced new table views that can use views instead of cells. However customizing things like NSButton is still way too difficult. For example on iOS you can set a layer style to add rounded rects. On the Mac this doesn’t work because a cell isn’t a view.
iOS users have become accustomed to animations and any app without them doesn’t feel fresh. So new Mac apps also needs animation, but this is much trickier to do than on iOS. iOS was built from the start with CoreAnimation, making it super easy to add delightful animations. In fact, on iOS UIView is just a thin wrapper over a CoreAnimation layer. On OS X, CoreAnimation was added in much much later as another way to use NSView and has to be turned on. Even worse some components completely fail to work with CoreAnimation, like web views. Other controls haves support for CoreAnimation, but it was hacked in and you are likely to find all sorts of weird edge cases (like try putting a button in a layer backed NSBox, it won’t work right). While iOS was built from the ground up with CoreAnimation, on OS X it’s always been half baked.
So many configurations
The bugginess between controls with and without CoreAnimation is a symptom of an even larger problem: the permutations of configs on the Mac. The Mac simply has more “stuff” than iOS. There is more to worry about, more to test, more to debug. On iOS there is a much smaller number of devices and number of device configurations.
For example on iOS you need to support both retina and non-retina displays. On the Mac, it is the same situation, but with more possibilities. What happens if the user has one display that is retina and one that isn’t? If you drag your app from a retina screen to a non-retina screen will it draw properly? Speaking of screens, what if they have them configured in an odd way, like one screen is to the upper right of their main screen? Does your app handle Mission Control properly? What about drag and drop? Undo? Printing? QuickLook? Spotlight Indexing?
With the age of the APIs, the amount of “stuff” (check out the NSWindow docs for a taste) and the variety of configurations there are simply more bugs in Cocoa than in UIKit. Throw in things that Mac apps were never designed for like sandboxing and CoreAnimation and you’ll find heaps of edge cases. With the intense competition in the mobile space, Apple simply won’t devote the resources to fix these outstanding issues on OS X. So it’s no surprise that we haven’t seen major advances in the desktop APIs, all the growth is in mobile.
Mac apps are trickier to build, and we aren’t likely to see that change in the near future. The APIs have more cruft, there are more hardware configurations, more OS features to worry about, and more hacked on APIs. If you are an iOS developer taking on a Mac project, make sure to give yourself ample time as it’s harder than it seems.