Skip to content

Instantly share code, notes, and snippets.

@AlanQuatermain
Created November 26, 2010 01:36
Show Gist options
  • Save AlanQuatermain/716167 to your computer and use it in GitHub Desktop.
Save AlanQuatermain/716167 to your computer and use it in GitHub Desktop.
A demonstration of some potential issues around the use of -[NSNotificationCenter addObserver:...usingBlock:].
@implementation MyObject
@synthesize observer;
- (void) storeObserverVariable
{
self.observer = [[NSNotificationCenter defaultCenter]
addObserverForName: @"TheNotification"
object: nil
queue: [NSOperationQueue mainQueue]
usingBlock: ^(NSNotification * note) {
// this reference to 'self' within the block causes 'observer'
// to retain 'self' which retains 'observer', which retains the
// block, which retains 'self' ...
if ( [self validateContents] == NO )
return;
[self sortContents];
[self performLayout];
}];
}
- (void) stopObservingInsideBlock
{
id tmpObserver = [[NSNotificationCenter defaultCenter]
addObserverForName: @"TheNotification"
object: nil
queue: [NSOperationQueue mainQueue]
usingBlock: ^(NSNotification * note) {
if ( [self validateContents] == NO )
{
// must remember to remove observer if there are multiple
// exit paths (which are often a bad thing in themselves,
// but...)
[[NSNotificationCenter defaultCenter] removeObserver: tmpObserver];
return;
}
[self sortContents];
[self performLayout];
// we must remove observer from within this block, because
// nothing else has a reference to it otherwise.
[[NSNotificationCenter defaultCenter] removeObserver: tmpObserver];
}];
}
- (void) repeatObservationsWithoutMemberVariable
{
id tmpObserver = [[NSNotificationCenter defaultCenter]
addObserverForName: @"TheNotification"
object: nil
queue: [NSOperationQueue mainQueue]
usingBlock: ^(NSNotification * note) {
if ( [self validateContents] == NO )
{
// must remember to remove observer if there are multiple
// exit paths (which are often a bad thing in themselves,
// but...)
[[NSNotificationCenter defaultCenter] removeObserver: tmpObserver];
// I want to sign up again, getting another observer object
// to release on the next invocation -- but how can I
// reference the block that's currently executing to pass
// it into this function?
return;
}
[self sortContents];
[self performLayout];
// we must remove observer from within this block, because
// nothing else has a reference to it otherwise.
[[NSNotificationCenter defaultCenter] removeObserver: tmpObserver];
// see above-- how do I re-register to keep receiving the
// events?
}];
}
- (void) onlyFlawlessWayOfDoingIt
{
typedef void (^notificationObserver_block)(NSNotification *);
// our observer block needs to reference itself, which means we
// need a variable to hold it which is defined up front. For
// clarity and safety (and sanity) we'll make it a __block
// variable:
__block notificationObserver_block observer_block = (notificationObserver_block)0;
// the observer needs to be assigned by the observer block when it
// signs up again, which means another __block variable:
__block id tmpObserver = nil;
// the observer block gets defined and assigned to its variable
// here:
observer_block = ^(NSNotification * note) {
if ( [self validateContents] )
{
[self sortContents];
[self performLayout];
}
// remove the existing observer
[[NSNotificationCenter defaultCenter] removeObserver: tmpObserver];
// signup again, because we want to keep receiving this
// notification
tmpObserver = [[NSNotificationCenter defaultCenter]
addObserverForName: @"TheNotification"
object: nil
queue: [NSOperationQueue mainQueue]
usingBlock: observer_block]; // references currently-executing block
};
// now we need to repeat the last line of our defined block to
// start the ball rolling:
tmpObserver = [[NSNotificationCenter defaultCenter]
addObserverForName: @"TheNotification"
object: nil
queue: [NSOperationQueue mainQueue]
usingBlock: observer_block];
}
@end
@JanC
Copy link

JanC commented Jul 22, 2015

In stopObservingInsideBlock, shouldn't id tmpObserver be __block id tmpObserver ? Otherwise it is released and is nil in the notification block

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment