Correct management of addObserverForName:object:queue:usingBlock:
I'm still new to blocks in objective-c and wondering if I have this psuedo code correct. I'm not sure if it's enough 开发者_开发百科to just remove the observer or if i have to call removeObserver:name:object:
-(void) scan {
Scanner *scanner = [[Scanner alloc] init];
id scanComplete = [[NSNotificationCenter defaultCenter] addObserverForName:@"ScanComplete"
object:scanner
queue:nil
usingBlock:^(NSNotification *notification){
/*
do something
*/
[[NSNotificationCenter defaultCenter] removeObserver:scanComplete];
[scanner release];
}];
[scanner startScan];
}
Update: I'm receiving intermittent EXC_BAD_ACCESS
from this block, so this can't be right.
Declare the scanComplete
variable before defining the block itself.
The reason why you need to do this is because you're trying to access a variable that doesn't exist within the block at the time of definition since the variable itself has not been assigned yet.
What is EXC_BAD_ACCESS
? Well, it's an exception that is thrown when you try to access a reference that doesn't exist. So that is exactly the case in your example.
So if you declare the variable before the block itself, then it should work:
-(void) scan {
Scanner *scanner = [[Scanner alloc] init];
__block id scanComplete;
scanComplete = [[NSNotificationCenter defaultCenter] addObserverForName:@"ScanComplete"
object:scanner
queue:nil
usingBlock:^(NSNotification *notification){
/*
do something
*/
[[NSNotificationCenter defaultCenter] removeObserver:scanComplete];
[scanner release];
}];
[scanner startScan];
}
You should not unregister in the register block. Instead, store the token returned from addObserverForName
(in this case, your scanComplete
) as an instance variable or in a collection that is an instance variable, and unregister later when you're about to go out of existence (e.g. in dealloc
). What I do is keep an NSMutableSet called observers
. So:
id ob = [[NSNotificationCenter defaultCenter]
addObserverForName:@"whatever" object:nil queue:nil
usingBlock:^(NSNotification *note) {
// ... whatever ...
}];
[self->observers addObject:ob];
And then later:
for (id ob in self->observers)
[[NSNotificationCenter defaultCenter] removeObserver:ob];
self->observers = nil;
Apple Document about this method:
The following example shows how you can register to receive locale change notifications.
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
self.localeChangeObserver = [center addObserverForName:NSCurrentLocaleDidChangeNotification object:nil
queue:mainQueue usingBlock:^(NSNotification *note) {
NSLog(@"The user's locale changed to: %@", [[NSLocale currentLocale] localeIdentifier]);
}];
To unregister observations, you pass the object returned by this method to removeObserver:. You must invoke removeObserver: or removeObserver:name:object: before any object specified by addObserverForName:object:queue:usingBlock: is deallocated.
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self.localeChangeObserver];
The scope of the block doesn't have permission to release the scanner object. If you're not using garbage collection, removing the release
and making the scanner autorelease ([[[Scanner alloc] init] autorelease]
) should do the trick.
You should also be able to safely move the call to removeObserver
outside of the block.
For the case of EXC_BAD_ACCESS
: Entering bt
in the console window after the application crashes will give you a backtrace, and should inform you where the error occurred.
精彩评论