Re: Is Apple's singleton sample code correct?
Re: Is Apple's singleton sample code correct?
- Subject: Re: Is Apple's singleton sample code correct?
- From: Shawn Erickson <email@hidden>
- Date: Sat, 26 Nov 2005 00:14:19 -0800
On Nov 25, 2005, at 7:50 PM, David Gimeno Gost wrote:
On 25 Nov 2005, at 19:05, Shawn Erickson wrote:
Consider reviewing what I use...
<http://www.cocoadev.com/index.pl?FTSWAbstractSingleton>
I don't get it, sorry.
I was answering in the point of view of an implementation like the
one Apple outlines in the documentation you noted. The one I use
moves init out to an initSingleton method that is private and not
advertised in headers (note the version of the website was
simplified, normally I have initSingleton in a private category in
the .m file).
Anyway it wasn't clear to me the alternate implementation that you
had in your head so I couldn't talk to that.
1. If I wanted to allow getting the singleton instance variable
through [[alloc] init] calls, then I would write +allocWithZone: as
follows:
+ (id) allocWithZone: (NSZone*) zone
{
@synchronized( self ) {
if ( sharedInstance == nil ) {
sharedInstance = [super allocWithZone: zone];
} else {
[sharedInstance retain];
}
}
return sharedInstance;
}
This will work correctly regardless of whether the -retain and -
release methods are overridden or not. Moreover, it encourages
client code to send a -release message to any singleton instance it
gets through [[alloc] init], as it is supposed to do with any
object returned by such methods, because failure to doing so can be
detected with the aid of debugging tools, as for any other resource
leak.
This is sufficient to ensure that memory for only one object is
allocated [1] on the first attempt and for all other attempts an
synthetic "allocation" takes place by adding a retain. What it
doesn't prevent against is the possibility of the singleton being
deallocated since code that does [[mySingleton alloc] init] will send
the "allocated" instance a release or autorelease message since they
are expected to follow the memory contract.
[1] At least when using normal messaging to the class to allocate an
instance.
If you changed your code to the following you could prevent your
singleton from being deallocated (assuming no one breaks the memory
contract).
+ (id) allocWithZone: (NSZone*) zone
{
@synchronized( self ) {
if ( sharedInstance == nil ) {
sharedInstance = [super allocWithZone: zone];
}
}
return [sharedInstance retain];
}
You can think of the implicit retain coming from [super
allocWithZone] as being the one related to the reference you are
stashing in sharedInstance and the explicit retains related to
allocate from the callers point of view... in other words the use of
"sharedInstance" and its related retain is an internal detail not one
to be touched by external memory management.
2. The -retain and -release methods shouldn't be overridden. There
is no point in doing so and the way it is done in the current
sample code guarantees that code breaking Cocoa's memory management
rules will go by unnoticed.
Correct they don't need to be overridden assuming you do something
like you did in your code above. I would however likely throw an
exception if somehow dealloc got called. This would be an active way
of detecting an over release scenario, at least possibly a little
closer to the source. An over retain or under release case will not
be detected since no memory leak would exist as a result, you would
have to watch retain counts and understand code to do that.
You may want to consider overriding retainCount to return UINT_MAX,
at least in release build, since I believe some optimization is done
by framework code when seen.
-Shawn
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden