开发者

How to deallocate view controllers that contains a view that references its parent

Here is a an interesting problem. I have a view controller, let's call it MyViewController. One of it's members is a a custom view, let's call that MyCustomView. MyCustomView also has a reference to its parent, MyViewController, since MyViewController is used as a delegate for the custom view. The problem occurs when MyViewController is unloaded, say due to a memory warning. Here is what happens:

First, viewDidUnload is called for MyViewController. It looks something like this:

- (void)viewDidUnload {
[super viewDidUnload];
    self.myCustomView = nil;
    self.someData = nil;
    ...
}

When self.myCustom开发者_运维问答View = nil is executed, it triggers myCustomView to be deallocated. MyCustomView's dealloc routine looks something like this:

- (void)dealloc {
    ...
    [delegate release];
    ...
    [super dealloc];
}

Recall from above that the delegate is MyViewController. If MyCustomView were released first, this would not be a problem, as the reference count for MyViewController would be greater than 1, but in this case MyViewController already has no other references to it. This causes MyViewController to be released, namely it's dealloc routine is called, which looks like:

- (void)dealloc { 
    [myCustomView release];
    [somedata release];
    ...
    [super dealloc];
}

As you can see, the members of MyViewController, namely, "somedata" get release BEFORE the viewDidUnload routine for MyViewController ever completes. As the dealloc routines for MyViewController and MyCustomView complete and we get back to finishing the viewDidUnload routine, we get to the line

self.somedata = nil;

Now, somedata is not nil but its value has already been release! This causes an exception.

This seems to be a critical flaw in reference counting. How do you deal with two-way references in objects like this that cause each other to be deallocated?

One answer is to always set the members to be nil in the dealloc routine. I don't like that answer. It's a lot of extra work and shouldn't be necessary most of the time. The other answer is to rearrange the order of viewDidUnload so that deallocation of child objects which may have backwards pointers always happens at the end. I don't like this solution either and it might not even work some of the time.

How do you get around this problem?


delegate members typically aren't reference counted. Typically the declaration is:

@property(nonatomic, assign) id<UITableViewDelegate> delegate

If you make your delegate like this you wont have the problem. And it should be safe since the parent view controller is only around as long as the child view - yes?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜