Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
493 views
in Technique[技术] by (71.8m points)

objective c - Dealloc Not Running When Dismissing Modal View from Block

Strange one here, dealloc is not being called when dismissed from inside a block. Code:

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

[self dismissModalViewControllerAnimated:YES];

 }];

Anyone know why this would be the case? How can i dismiss from inside the block and run dealloc at the same time?

I have tried self performselector but this did not make any difference.

Thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

(1) Your code is wrong (incomplete). When you issue addObserverForName: you must capture the returned value; this is the observer token. You store this somewhere (e.g. an instance variable):

self->observer = [[NSNotificationCenter defaultCenter] 
    addObserverForName:@"woohoo" object:nil queue:nil 
    usingBlock:^(NSNotification *note) 
        {
            //whatever
        }];

Later, when you're going out of existence, you remove that observer token from the notification center by calling removeObserver: with that token as argument. If you don't do that, you can crash later.

[[NSNotificationCenter defaultCenter] removeObserver:self->observer];

(2) But wait, there's more! Under ARC, when the block is copied, you'll get a retain cycle. This is because the stored observer token contains the block and is itself retaining self. I will give you three ways to break this retain cycle:

(a) Store the observer token as a weak reference:

__weak id observer;

(b) Store the observer token as a strong reference, but explicitly release it (by nilifying it) when you remove the observer:

[[NSNotificationCenter defaultCenter] removeObserver:self->observer];
self->observer = nil; // crucial

(c) Do the "weak-strong dance", like this, when you create the block (I am pretending that self is a FlipsideViewController):

__weak FlipsideViewController* wself = self;
observer = [[NSNotificationCenter defaultCenter] 
             addObserverForName:@"user.login" 
             object:nil queue:nil usingBlock:^(NSNotification *note) {
    FlipsideViewController* sself = wself;
    [sself dismissModalViewControllerAnimated:YES];
}];

Now, you might think that the "weak-strong dance" is an extreme approach, as one of my commenters implies. But it has one huge advantage: it is the only one of these three solutions that allows you to remove the observer in dealloc. With the other two solutions, dealloc will never be called until after you have called removeObserver: - and finding a better place to call it may not be easy.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...