When I use -addObserverForName: object: queue: usingBlock:
for NSNotificationCenter
in the -viewDidLoad:
method of my view controller, the -dealloc
method ends up not being called.
(When I remove -addObserverForName: object: queue: usingBlock:
, -dealloc
is called again.)
Using -addObserver: selector: name: object:
doesn't seem to have this problem. What am I doing wrong? (My project is using ARC.)
Below is an example of my implementation, in case I'm doing something wrong here:
[[NSNotificationCenter defaultCenter] addObserverForName:@"Update result"
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
updateResult = YES;
}];
Thanks in advance for any help.
I've tried adding the following (to no avail):
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if ([self isMovingFromParentViewController]) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
updateResult
is an instance variable which prevents the object from being deallocated as it is retained by that block.
In other words, you got a retain cycle. The object retains the block and the block retains the object.
You will need to create a weak or unsafe_unretained reference to that instance and its variable for loosing that relationship.
Add the following prior to your notification block:
__unsafe_unretained YouObjectClass *weakSelf = self;
or (in case you are on iOS5 and above)
__weak YouObjectClass *weakSelf = self;
Then, within that block, reference the object via that new weak reference:
[[NSNotificationCenter defaultCenter] addObserverForName:@"Update result"
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
weakSelf.updateResult = YES;
}];
Please note that retain-cycles are not a bad thing per se. Sometimes you actually want them to happen. But those are instances where you are certain that the cycle will be broken after a specific time (e.g. Animation Blocks). The cycle is broken once the block has executed and is removed from the stack.
This is very likely because you have a retain cycle.
This is typically the case when your block implicitly retain self, and self retains the block in a way. You will have a retain cycle as each one retains the other one, and their retainCount thus never reach zero.
You should activate the warning -Warc-retain-cycles
that will warn you about such issues.
So in your case, you are using the variable updateResult
, which I assume is an instance variable, and this implicitly retain self
. You should instead use a temporary weak variable to represent self, and use this in your block, so that it does not get retained and you break the retain cycle.
__block __weak typeof(self) weakSelf = self; // weak reference to self, unretained by the block
[[NSNotificationCenter defaultCenter] addObserverForName:@"Update result"
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
// Use weakSelf explicitly to avoid the implicit usage of self and thus the retain cycle
weakSelf->updateResult = YES;
}];
This is not retain cycle.
NSNotificationCenter
hold the block, block is hold self
. Because [NSNotificationCenter defaultCenter]
is a singleton living in all app life cycle, So it hold self
indirect.