Observer pattern in Objective-C: NSNotificationCenter

February 27, 2009 at 12:59 pm (iPhone development) (, , , )

I want to take a moment and thank the thoughtful developers at Apple (technically NextStep probably, but whatever) for the wonderfully simple, and elegantly powerful NSNotificationCenter. I won’t bother going over the API, there’s already many great blog posts on that (my favorite is here), but I wanted to raise awareness of it, and talk about how I’m using it in Spellwars…as well as discuss the potential pitfalls of abusing an event-based architecture.

The basic premise of the Broadcaster/Observer pattern is to decouple components, so that events can be fired and handled without everyone having to know about everyone else. This allows, for example, pieces of the UI (in my case, information labels that display stats of the selected spell) to update when a Spell is selected by the user, but the Spell objects don’t have to have explicit links back to the UI components. They just fire off their event (SpellSelected) and the UI controllers can listen for that event, then update the labels. It makes for a very clean implementation when done correctly.

When I finally got around to refactoring my super-hacky direct method invokations for this particular use case, I was able to remove 80% of the related code, and remove 90% of the complexity. Requiring back-pointers all over the code was making me nauseous. I was just about to implement my own solution when I came across several blog posts referring to said NSNotificationCenter, and once I saw the super-simple 3 method API I knew it was exactly the way to go. Nuff said.

Now, I will warn against going too far down the Broadcaster/Observer path, commonly called an Event-driven architecture, because I’ve seen it abused to the point of making code completely incoherent and impossible to understand or debug. Events are a natural way to pass information between unrelated objects, but between related objects, just invoke the methods directly. It more precisely expresses your intention as a code designer, and it also more precisely executes your intention.

At a startup I worked with over a year ago that shall remained unnamed, they were using Flex to build several web applications. Flex has a very well developed Event architecture, made even better by the Cairngorm micro-architecture. The problem with the product that the company was developing, is that they used Events for everything, absolutely everything. There were basically no direct method invocations on any objects, even when you naturally had the target object already in scope, and it was a child or some other natural relationship. This meant that every time flow control has to pass from one object to another, it required a listener to be added, an event to be defined, said event to be fired, and said listener to then be removed after. If that flow didn’t look obviously wrong to anyone else in the company, there’s nothing I could say to help them. It was such an absurd abomination I just didn’t even know where to begin.

I pretty much decided to begin by finding a new job.

Anyway, there was this one bug where some previous employee of the company had left a big nasty ball of mud with some problem in it, and because of the number of events fired, and the ability for multiple objects to respond to any event, it was just impractical to figure out what was going on, much less track down the problem.

Lesson: Just because you can, it doesn’t mean you should. Like all engineering tools, apply with discretion.

Permalink 2 Comments