从块中解除模态视图时Dealloc未运行

时间:2011-08-11 09:52:50

标签: objective-c ios

这里很奇怪,当从一个区块内被解雇时,dealloc没有被调用。代码:

[[NSNotificationCenter defaultCenter] addObserverForName:@"user.login" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {

[self dismissModalViewControllerAnimated:YES];

 }];

任何人都知道为什么会这样吗?我如何从块内部解散并同时运行dealloc?

我尝试过自我选择,但这没有任何区别。

由于

3 个答案:

答案 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:

reference

答案 2 :(得分:0)

我推荐你:Reference Counting of self in Blocks

该块将保留self,直到块被释放。因此,对于dealloc self,您需要删除观察者。