Re: How to allocate and delegate; or how to keep GC and the static analyzer happy

Christiaan Hofman <[email protected]>
Newsgroups gmane.comp.macosx.devel
Message-ID <[email protected]>
On Oct 9, 2009, at 12:27, Glen Low wrote:

> Hi All
>
> I have several cases of the following pattern in my code:
>
> - (void)start
> {
> 	[[Something alloc] initWithDelegate:self];
> }
>
> - (void)finishWithSomething:(Something*)something
> {
> 	[something release];
> }
>
> The intent of course is that the Something object calls back the  
> caller with finishWithSomething: and that does the cleanup. Several  
> UI classes can work this way e.g. -[UIActionSheet  
> initWithTitle:delegate:...].
>
> However as I understand it, there are several problems with this  
> pattern:
>
> 1.	The code is not GC friendly as between the end of start and the  
> beginning of finishWithSomething, there are no references to the  
> object, so it may be collected.
> 2.	The static analyzer in Xcode 3.2 doesn't like the construction,  
> thinking that the object is leaking from the start method.
>
> Of course I could keep a reference to the something object in a  
> field of the calling object, but I was hoping to avoid that -- the  
> calling object may invoke start multiple times before each  
> finishWithSomething:.
>
> Any suggestions?
>
>
>
>
>
>
> Cheers, Glen Low

This code is very wrong, both with managed memory and with GC. You  
MUST read the memory management rules in the docs.

The basic rule is that each object instance that should be living  
should have an (at least one) owner. The docs tell you how you can see  
when a caller gets and relinquishes ownership. The owner is  
responsible for 'releasing' the object when it's done. In your sample  
code, it seems like the receiver of -finishWithSomething: releases the  
Something instance, but it's not the owner, as it even doesn't have a  
reference to it. So this breaks these simple rules. Moreover, in - 
start it creates an instance that in managed memory is retained, but  
it does not take ownership over it (by keeping a reference to it), so  
that also breaks the rules.

So the normal procedure is that the object that creates the (retained)  
instance claims ownership and keeps a reference to it (directly or  
indirectly), and it then releases ownership when it's done with that  
object. That will guarantee that objects won't be deallocated or  
collected while it's still in use.

There are some cases where the object that creates the instance does  
not want to manage it further, e.g. for a temporary message window  
like an alert (or its controller). In that case typically the instance  
takes ownership over itself during the time it's in use. E.g. NSWindow  
can do this when you turn on isReleasedWhenClosed. The way to do this  
is that when the instance is 'shown' (or already when it's created) it  
'retains' itself, and it 'releases' itself again when it closes. It  
would be wrong to leave the release to some delegate, because the  
delegate isn't the owner. When using GC, using -retain and -release  
would not work for this, because those don't do anything, so you  
should use CFRetain and CFRelease.

Christiaan
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.