Ios 正确管理addObserverForName:object:queue:usingBlock:
我还不熟悉objective-c中的块,不知道这个psuedo代码是否正确。我不确定仅仅删除观察者是否足够,或者是否必须调用removeObserver:name:object:Ios 正确管理addObserverForName:object:queue:usingBlock:,ios,objective-c,cocoa,objective-c-blocks,Ios,Objective C,Cocoa,Objective C Blocks,我还不熟悉objective-c中的块,不知道这个psuedo代码是否正确。我不确定仅仅删除观察者是否足够,或者是否必须调用removeObserver:name:object: -(void) scan { Scanner *scanner = [[Scanner alloc] init]; id scanComplete = [[NSNotificationCenter defaultCenter] addObserverForName:@"ScanComplete"
-(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];
}
更新:我正在接收来自此块的间歇性
EXC\u BAD\u访问
,因此这不可能是正确的。在定义块本身之前声明scanplete
变量
之所以需要这样做,是因为您试图访问在定义时块中不存在的变量,因为变量本身尚未赋值
什么是EXC\u BAD\u访问
?当你试图访问一个不存在的引用时,会抛出一个异常。在你的例子中就是这样
因此,如果在块本身之前声明变量,那么它应该工作:
-(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];
}
块的作用域没有释放扫描仪对象的权限。如果您没有使用垃圾收集,那么删除
释放
并使扫描仪自动释放([[[scanner alloc]init]autorelease]
)应该可以做到这一点
您还应该能够将调用安全地移动到块外的removeObserver
对于
EXC\u BAD\u ACCESS
:在应用程序崩溃后在控制台窗口中输入bt
将提供回溯,并应通知您错误发生的位置。您不应在寄存器块中注销。相反,将从addObserverForName
返回的令牌(在本例中,您的scanComplete
)存储为实例变量或作为实例变量的集合,并在稍后您即将退出时注销(例如在dealloc
中)。我要做的是保留一个名为observators
的NSMutableSet。因此:
id ob = [[NSNotificationCenter defaultCenter]
addObserverForName:@"whatever" object:nil queue:nil
usingBlock:^(NSNotification *note) {
// ... whatever ...
}];
[self->observers addObject:ob];
后来:
for (id ob in self->observers)
[[NSNotificationCenter defaultCenter] removeObserver:ob];
self->observers = nil;
关于此方法的Apple文档: 以下示例显示如何注册以接收区域设置更改通知
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]);
}];
若要取消注册观测,请将此方法返回的对象传递给removeObserver:。必须在释放addObserverForName:object:queue:usingBlock:指定的任何对象之前调用removeObserver:或removeObserver:name:object:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self.localeChangeObserver];
您需要
\u块id扫描完成在ARC的世界里,关于使用\u block
避免捕获的评论不再成立。正确的是,\uu块
限定符修复了一个基本问题:定义块时,addObserverForName:…
尚未返回,因此捕获的值最多为nil
(在ARC下运行时,由于其隐式的变量声明自动为nil),或者未定义,用一个坏的访问来交换完全未定义的行为,在最坏的情况下…通过引用块内部的局部变量来移除观察者总是很卑鄙的。将返回的观察者令牌(此处,scanplete
)存储为实例变量;在ARC下,这应该是一个\u弱
实例变量,以防止自我保留循环。@matt为什么?skanky想要完全定位基于块的通知所涉及的所有移动部件的范围,这有什么意义呢?[scanner release]
应该在块外如果你想要一次性通知,我不明白为什么你不能在块中注销。同意上面的评论。我认为这个答案缺少的是“为什么”。我认为解释为什么“您不应该在注册块中注销”会有所帮助。尤其是因为苹果自己的API文档包括建议在该区块注销…@DanielGalasko,问题是如何防止崩溃,我的回答正确地说明了一种方法。公认的答案从另一端解决问题,即ob
的声明。这两个答案都是防止撞车的正确方法。