Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 正确管理addObserverForName:object:queue:usingBlock:_Ios_Objective C_Cocoa_Objective C Blocks - Fatal编程技术网

Ios 正确管理addObserverForName:object:queue:usingBlock:

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"

我还不熟悉objective-c中的块,不知道这个psuedo代码是否正确。我不确定仅仅删除观察者是否足够,或者是否必须调用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];
}

更新:我正在接收来自此块的间歇性
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扫描完成\u block
避免捕获的评论不再成立。正确的是,
\uu块
限定符修复了一个基本问题:定义块时,
addObserverForName:…
尚未返回,因此捕获的值最多为
nil
(在ARC下运行时,由于其隐式的变量声明自动为nil),或者未定义,用一个坏的访问来交换完全未定义的行为,在最坏的情况下…通过引用块内部的局部变量来移除观察者总是很卑鄙的。将返回的观察者令牌(此处,
scanplete
)存储为实例变量;在ARC下,这应该是一个
\u弱
实例变量,以防止自我保留循环。@matt为什么?skanky想要完全定位基于块的通知所涉及的所有移动部件的范围,这有什么意义呢?
[scanner release]
应该在块外如果你想要一次性通知,我不明白为什么你不能在块中注销。同意上面的评论。我认为这个答案缺少的是“为什么”。我认为解释为什么“您不应该在注册块中注销”会有所帮助。尤其是因为苹果自己的API文档包括建议在该区块注销…@DanielGalasko,问题是如何防止崩溃,我的回答正确地说明了一种方法。公认的答案从另一端解决问题,即
ob
的声明。这两个答案都是防止撞车的正确方法。