Perhaps you’ve got a situation like this: A ‘middleware’ type class in your application, which let’s say for argument’s sake keeps track of sales on your website, through a timer or some sort of push mechanism. You’ve also got some other UI classes which would like to be notified whenever there’s fresh data in this middleware class, so they can update their display.

One early approach I pursued in achieving something like this was to use an array of listeners. The middleware class maintained an array of listeners, and other classes could add themselves to that array. Whenever there was new data, the middleware class would iterate through the array, calling some method with a name like ‘MiddlewareUpdated’.

Basically, this was a classic observer pattern.

But this method had a lot of issues:

Memory management

Since the middleware was a singleton, and it’s list of listeners retained the other UI classes, they would never get released. A couple of solutions to this were tried:

  • Making this list hold weak/assign references to the other classes. This involved a hacky non-retaining subclass of NSMutableSet. And if we forgot to remove the UI classes from the listeners upon their dealloc, crashy crashy!
  • Making the UI classes remove themselves from the listeners array on their viewDidDisappear. This meant that if they were a hidden tab, we couldn’t update them, and all sorts of tradeoffs.

Lots of code

This method meant lots of boilerplate, error-prone code to keep track of the listeners in the middle ware, adding and removing them and sending them update notifications. Also all the UI classes needed to implement the MyMiddlewareDelegate protocol. And so on.

Enough!

So here I propose a simpler solution: using NSNotificationCenter. This way you can implement the observer pattern or the publish-subscribe pattern with much less error-prone boilerplate code and simpler memory management issues.

This solution ‘goes with the grain’ more with iPhone development, as it uses the pre-existing mechanisms, so there’s less reinventing the wheel going on here.

So let’s see how this works in practice. Here’s an example of my middleware class:

..header file..
NSString* const MyMiddlewareHasUpdatedNotification;

..implementation file..
NSString* const MyMiddlewareHasUpdatedNotification =
    @"MyMiddlewareHasUpdatedNotification";

- (void)notifyObservers {
    [[NSNotificationCenter defaultCenter]
        postNotificationName:MyMiddlewareHasUpdatedNotification
        object:nil];
}

So whenever it wants to notify anyone that it has new data, it calls the [self notifyObservers] method.

Now in the UI classes that want to observe the middleware class for any updates, in their viewDidLoad or initWithNibName or initWithCoder functions, you subscribe to the notifications like so:

// Start observing the middleware for changes
- (void)observeMiddleware {
    [[NSNotificationCenter defaultCenter]
        addObserver:self
        selector:@selector(middlewareUpdated:)
        name:MyMiddlewareHasUpdatedNotification
        object:nil];
}

// When we're done, remove ourselves as an observer.
// That's it for memory management!
- (void)dealloc {
    [[NSNotificationCenter defaultCenter]
        removeObserver:self];
    [super dealloc];
}

// On startup, get the current state of the middleware
// and listen for future updates  
- (void)viewDidLoad {
    [self observeMiddleware];
    [self getInitialLoadFromMiddleware];
    [super viewDidLoad];
}

// Update the UI to reflect the latest data
- (void)getDataFromMiddleware {
    self.something = [[MyMiddleware instance] something];
    [self.tableView reloadData];
}

// Upon startup, get the initial data from the middleware class
- (void)getInitialLoadFromMiddleware {
    [self getDataFromMiddleware];
}

// This'll get called whenever the middleware has updated
- (void)middlewareUpdated:(NSNotification*)notification {
    [self getDataFromMiddleware];
}

The above example is slightly longer than necessary to illustrate how I prefer to grab the initial data and listen for later updates neatly. Really the only interesting parts are the observeMiddleware and middlewareUpdated methods.

Thanks for reading! And if you want to get in touch, I'd love to hear from you: chris.hulbert at gmail.