Take the 2-minute tour ×


We're developing a custom EventEmitter inspired message system in Objective-C. For listeners to provide callbacks, should we require blocks or selectors and why?

Which would you rather use, as a developer consuming a third party library? Which seems most in line with Apple's trajectory, guidelines and practices?


We're developing a brand new iOS SDK in Objective-C which other third parties will use to embed functionality into their app. A big part of our SDK will require the communication of events to listeners.

There are five patterns I know of for doing callbacks in Objective-C, three of which don't fit:

  • NSNotificationCenter - can't use because it doesn't guarantee the order observers will be notified and because there's no way for observers to prevent other observers from receiving the event (like stopPropagation() would in JavaScript).
  • Key-Value Observing - doesn't seem like a good architectural fit since what we really have is message passing, not always "state" bound.
  • Delegates and Data Sources - in our case, there usually will be many listeners, not a single one which could rightly be called the delegate.

And two of which that are contenders:

  • Selectors - under this model, callers provide a selector and a target which are collectively invoked to handle an event.
  • Blocks - introduced in iOS 4, blocks allow functionality to be passed around without being bound to an object like the observer/selector pattern.

This may seem like an esoteric opinion question, but I feel there is an objective "right" answer that I am simply too inexperienced in Objective-C to determine. If there's a better StackExchange site for this question, please help me by moving it there.

UPDATE #1 — April 2013

We chose blocks as the means of specifying callbacks for our event handlers. We're largely happy with this choice and don't plan to remove block-based listener support. It did have two notable drawbacks: memory management and design impedance.

Memory Management

Blocks are most easily used on the stack. Creating long-lived blocks by copying them onto the heap introduces interesting memory management issues.

Blocks which make calls to methods on the containing object implicitly boost self's reference count. Suppose you have a setter for the name property of your class, if you call name = @"foo" inside a block, the compiler treats this as [self setName:@"foo"] and retains self so that it won't be deallocated while the block is still around.

Implementing an EventEmitter means having long-lived blocks. To prevent the implicit retain, the user of the emitter needs to create a __block reference to self outside of the block, ex:

__block *YourClass this = self;
[emitter on:@"eventName" callBlock:...
   [this setName:@"foo"];...

The only problem with this approach is that this may be deallocated before the handler is invoked. So users must unregister their listeners when being deallocated.

Design Impedance

Experienced Objective-C developers expect to interact with libraries using familiar patterns. Delegates are a tremendously familiar pattern, and so canonical developers expect to use it.

Fortunately, the delegate pattern and block-based listeners are not mutually exclusive. Although our emitter must be able to be handle listeners from many places (having a single delegate won't work) we could still expose an interface which would allow developers to interact with the emitter as though their class was the delegate.

We haven't implemented this yet, but we probably will based on requests from users.

UPDATE #2 — October 2013

I'm no longer working on the project that spawned this question, having quite happily returned to my native land of JavaScript.

The smart developers who took over this project decided correctly to retire our custom block-based EventEmitter entirely. The upcoming release has switched to ReactiveCocoa.

This gives them a higher level signaling pattern than our EventEmitter library previously afforded, and allows them to encapsulate state inside of signal handlers better than our block-based event handlers or class-level methods did.

share|improve this question
Given that this is a design/"white-board" sort of a question, Programmers might have been a better place for it -- just to inform you of another option. –  Josh Caswell Jun 14 '12 at 18:50
Thanks Josh, I looked at Programmers and thought about posting this over there, but it looked to be much more language-agnostic type questions. Since this was language/system specific I thought it would go here, but as I mentioned in the question, I'm certainly not sure of that. –  jimbojw Jun 14 '12 at 20:38
add comment

4 Answers

up vote 7 down vote accepted

Personally, I hate using delegates. Because of how objective-C is structured, It really clutters code up If I have to create a separate object / add a protocol just to be notified of one of your events, and I have to implement 5/6. For this reason, I prefer blocks.

While they (blocks) do have their disadvantages (e.x. memory management can be tricky). They are easily extendable, simple to implement, and just make sense in most situations.

While apple's design structures may use the sender-delegate method, this is only for backwards compatibility. More recent Apple APIs have been using blocks (e.x. CoreData), because they are the future of objective-c. While they can clutter code when used overboard, it also allows for simpler 'anonymous delegates', which is not possible in objective C.

In the end though, it really boils down to this: Are you willing to abandon some older, more dated platforms in exchange for using blocks vs. a delegate? One major advantage of a delegate is that it is guaranteed to work in any version of the objc-runtime, whereas blocks are a more recent addition to the language.

As far as NSNotificationCenter/KVO is concerned, they are both useful, and have their purposes, but as a delegate, they are not intended to be used. Neither can send a result back to the sender, and for some situations, that is vital (-webView:shouldLoadRequest: for example).

share|improve this answer
We target iOS 4.x and up, so blocks should be supported on our targets. –  jimbojw Jun 13 '12 at 21:33
add comment

I think the right thing to do is to implement both, use it as a client, and see what feels most natural. There are advantages to both approaches, and it really depends on the context and how you expect the SDK to be used.

The primary advantage of selectors is simple memory management--as long as the client registers and unregisters correctly, it doesn't need to worry about memory leaks. With blocks, memory management can get complex, depending on what the client does inside the block. It's also easier to unit test the callback method. Blocks can certainly be written to be testable, but it's not common practice from what I've seen.

The primary advantage of blocks is flexibility--the client can easily reference local variables without making them ivars.

So I think it just depends on the use case--there is no "objective right answer" to such a general design question.

share|improve this answer
Thanks for calling out the memory-management hassle; it's good to consider that. Implementing both and doing an A/B test is not going to work for this project unfortunately since it's nearly impossible to take features out of a library once you have users (which we'll have for business reasons pretty much immediately). –  jimbojw Jun 14 '12 at 20:32
I didn't mean you should do an A/B test. I mean you should write client code against it yourself. It's like doing test-driven development--actually using your interfaces as a client helps you design better interfaces. –  Christopher Pickslay Jun 15 '12 at 18:08
add comment

A thing about a library is, that you can only to some extend anticipate, how it will be used. so you need to provide a solution, that is as simple and open as possible — and familiar to the users.

  • For me all this fits best to delegation. Although you are right, that it can only have on listener (delegate), this means no limitation, as the user can write a class as delegate, that knows about all desired listeners and informs them. Of course you can provide a registering class. that will call the delegate methods on all registered objects.
  • Blocks are as good.
  • what you name selectors is called target/action and simple yet powerful.
  • KVO seems to be a not optimal solution for me as-well, as it would possibly weaken encapsulation, or lead to a wrog mental model of how using your library's classes.
  • NSNotifications are nice to inform about certain events, but the users should not be forced to use them, as they are quite informal. and your classes wont be able to know, if there is someone tuned-in.

some useful thoughts on API-Design: http://mattgemmell.com/2012/05/24/api-design/

share|improve this answer
Thanks for responding. In our case delegation doesn't really match because many different entities will be emitting through it with many different handlers listening for different kinds of events. I read Matt's article. Sadly he doesn't mention blocks at all. –  jimbojw Jun 13 '12 at 21:37
I still think, that delegation/protocols would work for you. the messages that would be send would have to fulfill a certain protocol. It could be informal as-well. It doesn't make much difference, if a sender must package it's message in a certain block or conforming to a certain protocol. I dont say, you shouldnt use blocks. i.e. AFNetworking is doing it great. but with blocks you have to anticipate, how the user will want to use it, as you have to offer him the blocks parameters (yes, I know about __block, but that really isnt elegant). –  vikingosegundo Jun 13 '12 at 21:45
add comment

Great writeup!

Coming from writing lots of JavaScript, event-driven programming feels way cleaner than having delegates back and forth, in my personal opinion.

Regarding the memory-managing aspect of listeners, my attempt at solving this (drawing heavily from Mike Ash's MAKVONotificationCenter), swizzles both the caller and emitter's dealloc implementation (as seen here) in order to safely remove listeners in both ways.

I'm not entirely sure how safe this approach is, but the idea is to try it 'til it breaks.

share|improve this answer
add comment

Your Answer


