问题
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.
回答1:
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];
}
回答2:
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;
回答3:
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];
回答4:
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.
来源:https://stackoverflow.com/questions/4550798/correct-management-of-addobserverfornameobjectqueueusingblock