这里很奇怪,当从一个区块内被解雇时,dealloc没有被调用。代码:
[[NSNotificationCenter defaultCenter] addObserverForName:@"user.login" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self dismissModalViewControllerAnimated:YES];
}];
任何人都知道为什么会这样吗?我如何从块内部解散并同时运行dealloc?
我尝试过自我选择,但这没有任何区别。
由于
答案 0 :(得分:1)
(1)您的代码错误(不完整)。当您发出addObserverForName:
时,您必须捕获返回的值;这是观察者令牌。您将其存储在某处(例如实例变量):
self->observer = [[NSNotificationCenter defaultCenter]
addObserverForName:@"woohoo" object:nil queue:nil
usingBlock:^(NSNotification *note)
{
//whatever
}];
稍后,当您不再存在时,通过使用该标记作为参数调用removeObserver:
,从通知中心删除该观察者标记。如果你不这样做,你可以稍后崩溃。
[[NSNotificationCenter defaultCenter] removeObserver:self->observer];
(2)但等等,还有更多!在ARC下,复制块时,您将获得保留周期。这是因为存储的观察者令牌包含块并且本身保留自身。我会给你三种方法来打破这个保留周期:
(a)将观察者令牌存储为弱引用:
__weak id observer;
(b)将观察者令牌存储为强引用,但在移除观察者时明确释放它(通过取消它):
[[NSNotificationCenter defaultCenter] removeObserver:self->observer];
self->observer = nil; // crucial
(c)当你创建块时(我假装self
是FlipsideViewController),做这样的“弱强舞”:
__weak FlipsideViewController* wself = self;
observer = [[NSNotificationCenter defaultCenter]
addObserverForName:@"user.login"
object:nil queue:nil usingBlock:^(NSNotification *note) {
FlipsideViewController* sself = wself;
[sself dismissModalViewControllerAnimated:YES];
}];
现在,你可能认为“弱强舞”是一种极端的方式,正如我的一位评论者暗示的那样。但它有一个巨大的优势:它是这三个解决方案中唯一一个允许你删除dealloc
中的观察者。使用其他两个解决方案,{<1}}将永远不会被调用,直到之后调用dealloc
- 并且找到一个更好的地方来调用它可能并不容易。
答案 1 :(得分:0)
这可能与UIKit不是完全线程安全有关吗? UIKit应仅用于主线程......
如果是这样,我建议使用:
performSelectorOnMainThread:withObject:waitUntilDone:
答案 2 :(得分:0)
我推荐你:Reference Counting of self in Blocks
该块将保留self
,直到块被释放。因此,对于dealloc self
,您需要删除观察者。