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
(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.
I refer you to: Reference Counting of self in Blocks
The block will retain self
until the block is released. So to dealloc self
, you'll need to remove the observer.
Could this be related to UIKit being not completely thread-safe? UIKit should be only used on the main thread...
If so, I would suggest using:
performSelectorOnMainThread:withObject:waitUntilDone:
(reference)
精彩评论