Reputation: 7687
I have a container UIViewController
which does the following when removing one of its children:
- (void)removeChildWithIndex:(NSUInteger)Index {
@autoreleasepool {
ChildViewController *child = [_children objectAtIndex:Index];
//Remove the child from the VC hierarchy
[child willMoveToParentViewController:nil];
[child.view removeFromSuperview];
[child removeFromParentViewController];
//Remove the child from array
[_children removeObjectAtIndex:Index];
}
//Post a notification for anyone who might care
[[NSNotificationCenter defaultCenter] postNotificationName:RemovedChildNotification object:self];
}
The root of my problem is that child
is not being dealloc
ed at the end of the @autoreleasepool
block, but instead is released a little bit later (by the looks of it after the RunLoop has a chance to process an internal list of outstanding events):
This ordinarily wouldn't be a problem, but one object which is observing the NSNotification
sent out at the end of the function above is relying on the child
being dealloc
ed before it receives the notification.
Can anybody explain/link me to some documentation to help me understand why child
isn't released immediately?
Alternatively, if I have no choice about when child
is dealloc
ed, can anybody suggest a clean way of delaying my notification until after the dealloc
? I suppose I could put a call in [ChildViewController dealloc]
to inform the parent of its demise and fire off the notification at that point, but that's a pretty dirty way of doing it...
Upvotes: 3
Views: 1674
Reputation: 1037
Try sending the notification in the next runloop iteration:
- (void)removeChildWithIndex:(NSUInteger)Index
{
ChildViewController *child = [_children objectAtIndex:Index];
//Remove the child from the VC hierarchy
[child willMoveToParentViewController:nil];
[child.view removeFromSuperview];
[child removeFromParentViewController];
[child didMoveToParentViewController:nil];
//Remove the child from array
[_children removeObjectAtIndex:Index];
//Post a notification for anyone who might care
[self performSelector:@selector(_postRemoveChildNotification) withObject:nil afterDelay:0.0f];
}
- (void)_postRemoveChildNotification
{
[[NSNotificationCenter defaultCenter] postNotificationName:RemovedChildNotification object:self];
}
Upvotes: 2
Reputation: 10175
The main problem in your code is the autoreleasepool
whcih
Autorelease pool blocks provide a mechanism whereby you can relinquish ownership of an object, but avoid the possibility of it being deallocated immediately
So basically the autoreleasepool
will help you removing the ownership of the objects inside the autorelease block but will guarantee that they are not release immediately.
So what you have to do is remove the autoreleasepool
block and let your code as is and at the bottom of your code you can also make the child nil child = nil
this will also help your class that receive the notification.
Also don't write code that will base on the fact that some objects will be deallocated when your code is executed. The SO can't guarantee that one object will be deallocated immediately after a method is called. This is just a bad practice, if you can you should rethink your implementation.
Upvotes: 0