Method
- (void)addObserver:(id)observer
forName:(NSString *)name
object:(id)object
queue:(NSOperationQueue *)queue
usingBlock:(void (^)(NSNotification *note, __weak id observer))block;
Usage
[[NSNotificationCenter defaultCenter] addObserver:self
forName:NSSomeNotificationName
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note, __weak id observer) {
NSLog(@"self: %@", observer); //Look Ma, no leaks!
}];
Discussion
The observer object takes the place of the token in the current block-based API and works like the observer in the selector-based API. The block is retained by NSNotificationCenter only for as long as the observer exists. NSNotificationCenter does not retain the observer, so if all other references are deleted it will be destroyed, along with the block.
For convenience, a weak reference to the observer is passed as a second parameter to the block. The block can use this to refer to the observer (which would be 'self' in typical usage) to avoid doing the weakify dance.
There is no need to call removeObserver: in the observer's dealloc method, as the observer reference is cleaned up automatically when the observer is released. To remove the observer before it is released, you can use the existing removeObserver: APIs.
@nicklockwood Joachim made a pretty good case against special-casing self in the blog comments.
Explicit storage duration is a new idea. But, this spreads the solution (variable declarations) potentially far away from the block. Of course, we could adopt the convention to always declare new variables right before a block declaration. That's something to think about.
Personally I think the solution is some way to express your intent that a block does not capture (self/whatever). And then, if clang finds itself doing that thing that you explicitly expected not to happen, you get a build error.