NSNotificationCenter is Probably an Anti-Pattern
This week’s iOS Dev Weekly linked to a tweet from Ben Sandofsky about an important change to NSNotificationCenter in iOS 9:
In OS X 10.11 and iOS 9.0 NSNotificationCenter and NSDistributedNotificationCenter will no longer send notifications to registered observers that may be deallocated. If the observer is able to be stored as a zeroing-weak reference the underlying storage will store the observer as a zeroing weak reference, alternatively if the object cannot be stored weakly (i.e. it has a custom retain/release mechanism that would prevent the runtime from being able to store the object weakly) it will store the object as a non-weak zeroing reference. This means that observers are not required to un-register in their deallocation method. Link.
I can’t remember where I heard the following fact (I think it was during one of the WWDC 2015 talks), but it’s my understanding that a deallocated-without-unregistering NSNotificationCenter observer is one of the top causes of crashes in third-party iOS/OS X software. Assuming this is true, a thought struck me today: how much less common would this crash have been if there had been an easier alternative than KVO all this time?
In Foundation, there are only two first-party ways to propagate model changes from one to many observers: KVO and NSNotificationCenter. Both of them are prone to cause crashes when misused, but I’d argue that KVO is harder to use correctly. It’s not unreasonable to imagine that many developers opt for NSNotificationCenter as the least bad option.
It may sound surprising to some that I’d refer to NSNotificationCenter as a “bad” option. I should clarify that I think NSNotificationCenter is a fine API when used for events of a truly global nature. An argument for or against NSNotificationCenter is like an argument for or against a singleton. As I’ve joked on Twitter:
Use a singleton when you need the Sun, not an overhead lamp.
Similarly, I think NSNotificationCenter is best suited for events whose origin is so far outside the scope of local control flow that it would be awkward or even silly to use anything else. The NSNotificationCenter version of my singleton tweet is:
NSTheSunDidRiseNotification, not NSSomebodysPassengerPushedTheFlightAttendantButtonNotification.
In practice I have a hard time justifying the use of NSNotificationCenter for anything besides events vended by the OS, like UIKeyboardWillShowNotification
.
I often see NSNotificationCenter used as a clearing house for all the one-to-many relationships between model objects and observers in an app. I think this is probably an anti-pattern. This pattern obligates observers to decide when to ignore notifications.
Consider a Twitter client with a TweetWasLikedNotification
. The observers for that notification not only need to know the ID of the liked tweet, but also the local account from which that like action was taken, and/or perhaps the NSManagedObjectContext to which the tweet belongs, etc. Global knowledge belongs at a higher layer in the application. Better still is a design that couples model and observer more closely with an explicit relationship (perhaps a delegate protocol) that doesn’t require such knowledge in the first place.
I have considered using a custom center, instead of the defaultCenter()
singleton, but that seems like a half-baked implementation of a design that would be better expressed via a weak-referencing collection of SomeCustomObserverProtocol
delegates.
Until Apple provides a Swift-native, first-party way to implement a one-to-many observer pattern, I will continue to use NSObject subclasses and KVO. I’ve been trying to think of ways to abstract out the particulars of NSObject/KVO relationships, keeping the higher-level APIs cleaner and more friendly. Here’s an example of what I mean, posted to GitHub. For a direct-download link of the Xcode playground, click here. I haven’t tried this in production yet, but the idea is to map NSObjects to adapter/observers who produce “view model” structs in response to KVO updates, passing those structs onto their delegates. This lets me use value types instead of the actual model objects for UI updates, without having to abandon KVO as the underlying infrastructure.
Steven Sinofsky on Why Remote Engineering is So Difficult
I have spent a lot of time trying to manage work so it is successful outside of a single location. I’ve had mixed results and have found only three patterns which are described below.
…
The first pattern is good to know, just not scalable or readily reproducible. That is when you have a co-located and functioning team and members need to move away for some reason then remote work can continue pretty much as it has before. This assumes that the nature of the work, the code, the project all continue on a pretty similar path.
…
The second pattern that works is when a project is based on externally defined architectural boundaries. In this case little knowledge is required that span the seam between components. What I mean by externally defined is that the API between the major pieces, separated by geography, is immutable and not defined by the team.
…
The third pattern that works is that those working remotely have projects that have essentially no short term or long term connection to each other. This is pretty counter-intuitive. It is also why startups are often the first places to see remote work as challenging, simply because most startups only work on things that are connected.
The entire article is worth your time if you’re thinking about building distributed teams.
Saving the iPad
What follows is a very brief summary of what I believe are the biggest obstacles holding back the iPad and the App Store, and what I believe Apple can do to improve things.
Three Big Problems
The App Store Strangles Pro Apps at Birth
The App Store is designed, from what it features to what it permits, to promote cheap, shallow, candy apps. It discourages developers from ever starting ambitious apps, both passively and actively. Instead apps are trending towards ever cheaper prices. Serious damage is being done to customer expectations about the value of a piece of software.
The iPad is a Mystery
The iPad was marketed as a third category of device, neither a phone nor a PC, but Apple has never managed to articulate what that third category really is. Instead the iPad has drifted along in the sucking wind the iPhone leaves in its wake. Meanwhile the Mac, which was designed with rigorous intention since its earliest days in the 1980s, is selling at record levels. Let that sink in.
iOS Was Not Designed for Multi-Tasking
iOS user interface paradigms are not suited to using more than one app at a time. iOS was designed almost a decade ago for a phone whose screen is smaller than the gap between the iPad Pro’s app icons. Recent additions like iOS 8’s app extensions or iOS 9’s split-screen multi-tasking are essentially bolted-on, aftermarket parts.
How Apple’s Problems Affect Developers
Because of the three big problems above, developers are confused and disheartened:
- The App Store discourages developers from ever starting complex projects. It would be like trying to help your date with his taxes in a dance club on New Years Eve. Instead they’re caught in a prisoners dilemma, selling underpowered apps for free or worse.
- The iPad doesn’t make sense to consumers, which means it also doesn’t make sense to developers. Until something changes, the primary use case for the iPad will be writing reviews about the iPad. For any other serious work, you will be more competently helped by a Mac.
- Apple’s public APIs and human interface guidelines encourage developers to use scaled-up versions of iPhone layouts on the iPad. The result is an awkard mess of usability issues, instead of the rigorous simplicity of the earliest Macs. Developers depend upon Apple to establish appropriate idioms to imitate. Apple has failed to provide meaningful idioms worth imitating.
Solutions
My proposed solutions are really hand-wavy, because a) this is a blog post, b) my kid has finally fallen asleep and I want to watch something stupid on TV before I fall asleep, and c) these are really hard problems that deserve top-notch thinking. For what they’re worth, here’s what I think Apple should do to improve the iPad’s chances:
Gatekeeper for iOS
Apple should expand the Gatekeeper program to iOS.1 Developers should be allowed to sell Gatekeeper-signed apps directly to customers outside of the App Store.
These apps would be just as secure as apps published on the App Store. I recommend that Gatekeeper iOS apps be subject to the same API restrictions, privacy permissions, and sandboxing as apps distributed on the iOS App Store. Apple would retain the ability to nuke an app at will in the case of a catastrophic breach (which to my knowledge has never happened on the Mac’s Gatekeeper program).
The only difference would be that Apple no longer mediates the developer/customer relationship. Developers would be able to use all of the business techniques that have been practiced by software businesses on the Mac: trial versions, paid upgrades, special licensing, etc.
The point of this is not to use Gatekeeper per se, but to remove Apple as an obstacle to common business practices. No one believes that after all these years Apple will suddenly do everything developers want. It’s more realistic to suggest that Apple simply expand an existing program to another platform, and call it a day.
if developers can’t make money selling iOS productivity apps via Gatekeeper, then their failures can no longer be blamed on Apple.
Position the iPad as a Mac-Killer
Apple is confusing themselves and everyone else by positioning the iPad as a third category of device. No one can figure out what that means, least of all Apple. Instead the iPad should be positioned as an unapologetic replacement for a Mac. The iPad should be to the Mac what the Mac was to the PCs it destroyed. If Apple wants people to strap a hardware keyboard onto their iPad Pro, put it on a desk, and use more than one app at a time, then goddammit that is a replacement for a Mac. Imagine if back in 2009 at the unveiling of the first iPad, Steve Jobs had said something along the lines of, “Why iPad? Well, because we think in a few years you’re not gonna want a Mac anymore.”
Release a “padOS”
The iPad is walking backwards into all the use-cases for which the Mac was designed with deliberate intention from the Mac’s earliest days. But because of Apples bolted-on approach, tacking features onto a decade-old smartphone OS, the result is far removed from Apple’s best work. The design principles of an iPhone simply don’t scale up to an iPad, in the same way that the design principles of an iMac don’t scale up to an Apple TV. The iPad should be rebooted with a set of fresh design principles that are aimed at answering the question: How can a multi-tasking touchscreen device fully replace a Mac? These principles would guide both Apple and third-party developers, and in turn would spur a desire in customers to leave behind a PC for an iPad without looking back.
-
Credit where credit is due: I first encountered the idea of expanding Gatekeeper to iOS from Pieter Omvlee, founder of Bohemian Coding. ↩
Time Zones Version 1.2 Available Today
Version 1.2 of my Time Zones app for iPhone is available today. Here’s what’s new:
- New - Added home screen shortcuts to launch directly into Quick Check mode. Quick Check mode lets you look up future dates and times and easily compare them across multiple locations. With the new home screen shortcuts, you can jump straight to “this time tomorrow”, or to the custom date picker screen. Home screen shortcuts are only available on iPhone 6s and iPhone 6s Plus.
- New - You can select which cities will appear in the Today widget. Tap a city in your list of cities in the app to see this option in the options menu.
- New - Disabled ads for all users. Thanks to everyone who purchased Time Zones Pro, I really appreciate your support. The ads made such small amounts of money that they only served to enshitten an app I was making for my own personal use. Hopefully you can get some use out of it, too.
- Fix - Fixed an issue that caused wrong time offsets (the plus/minus hour text) when using Quick Check mode during Daylight Savings Time transitions. Thanks to the folks who reported this issue. I’m sorry it took so long to get fixed.
- Fix - Fixed a crasher that affected some users during Quick Check mode.
- Change - Various minor UI improvements.
Download Time Zones on the App Store.
Are You a Workaholic?
A couple of months ago I discovered that I am a work addict. Work-addiction is a real condition that affects many people. Discovering that I am addicted to work helped me to understand some causes of all sorts of problems with my life and marriage. Because work is a necessary part of normal life, and a source of pride for many, work addiction can easily go undiagnosed. If you answer “yes” to a lot of the following questions, you might be a work addict, too. I answered “yes” to nineteen of them.
Twenty Questions: How Do I Know If I’m A Workaholic?
- Do you get more excited about your work than about family or anything else?
- Are there times when you can charge through your work and other times when you can’t?
- Do you take work with you to bed? On weekends? On vacation?
- Is work the activity you like to do best and talk about most?
- Do you work more than 40 hours a week?
- Do you turn your hobbies into money-making ventures?
- Do you take complete responsibility for the outcome of your work efforts?
- Have your family or friends given up expecting you on time?
- Do you take on extra work because you are concerned that it won’t otherwise get done?
- Do you underestimate how long a project will take and then rush to complete it?
- Do you believe that it is okay to work long hours if you love what you are doing?
- Do you get impatient with people who have other priorities besides work?
- Are you afraid that if you don’t work hard you will lose your job or be a failure?
- Is the future a constant worry for you even when things are going very well?
- Do you do things energetically and competitively including play?
- Do you get irritated when people ask you to stop doing your work in order to do something else?
- Have your long hours hurt your family or other relationships?
- Do you think about your work while driving, falling asleep or when others are talking?
- Do you work or read during meals?
- Do you believe that more money will solve the other problems in your life?
Those questions come from this website, which has religious references that creep me out so I don’t offer any guarantees about whether or not you will find help there. I found some of their practical recommendations quite helpful. Pick and choose what seems right for you.
Things That Have Helped Me
You can’t fix it by yourself. – It’s important to talk to your family and friends so they know what you’re dealing with. When you are an addict, you need the support of other people to help you build healthy new habits.
Get outside. – Take a 30 minute walk in the afternoons when the rest of your coworkers are heads-down at their desks. As you walk think about things you can’t turn into more work. Make a list of these things before you go out on your walk, as a backup plan if your mind gets stuck in the usual ruts.
Get out of town. – Take a quick day trip every weekend, it doesn’t matter where. Don’t bring your laptop. Silence your work notifications. Go to a science or history museum. Take a hike in the woods. Visit an aquarium. Eat at that restaurant you would never have tried otherwise. Put yourself someplace that is unfamiliar and far removed from your work routines.