gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: sync.m


From: David Chisnall
Subject: Re: sync.m
Date: Sun, 28 Feb 2010 14:01:08 +0000

On 28 Feb 2010, at 08:42, address@hidden wrote:

>> Although this works, it is a really, really bad way of creating a singleton.
> 
> I copied it from the apple developer pages...

This is rarely a good idea, unfortunately.  Apple's API documentation is very 
good, but their example code doesn't seem to have been written by programmers 
so it often does things in ways that are more appropriate to thedailywtf.com 
than developer.apple.com.

> I thought +initialize would be called on program startup for every
> class. I want to be able to create my singleton on demand since it has
> a rather large memory footprint. If that works with the method you
> propose I'm fine with it.

There are two methods on a class that will be called by the runtime; +load and 
+initialize.  The +load method is called as soon as the class is loaded.  At 
this point, you can guarantee that the class and its superclasses are loaded, 
but you can't guarantee anything else about the state of the system.  

Generally speaking, any code using +load is wrong.  I think I've used it twice, 
and both times it's been for something quite ugly.  

The +initialize method is much safer.  It is called, in a thread-safe way, by 
the runtime when the first message is sent to the class.  The first message 
sent to a class is usually something like +alloc, +new, or +sharedInstance.  
Creating the singleton in +initialize will create it in the right place.  

I was going to suggest that you look in Erik Buck's Cocoa Design Patterns, but 
it turns out that he also does it wrong - his non-thread-safe solution is more 
complex and slower than the thread-safe one, which is a shame; I'd have 
expected better from an old NeXT programmer.  

>> Your +allocWithZone: method should really check that it's not a
>> subclass, before returning the singleton.
> 
> I don't want this class to be subclassed.

As Richard said, the best solution in this case is to throw an exception if the 
+allocWithZone: method is called on a subclass.  This will prevent any 
subclasses from working.  

> How would you deallocate your singleton then?

That's a good question.  The answer in your current code is 'prematurely'.  You 
are not retaining your singleton when it is returned, so either calling code 
will treat it like a singleton and never -release it, or it will -release it 
causing it to be destroyed and your global to be a dangling pointer.

Erik suggests implementing a +attemptDealloc method that calls -release if 
-retainCount returns 1, but that's a messy and silly idea.  

If you want to be able to deallocate and recreate the singleton, be aware that 
you need to set the static pointer to nil.  You also need to rewrite your 
+sharedInstance method like this (where instanceLock is an NSLock created in 
+initialize and sharedInstance is the instance pointer, both are file statics):

+ (id)sharedInstance
{
        id obj;
        [instanceLock lock];
        obj = sharedInstance;
        if (nil == obj)
        {
                obj = sharedInstance = [self new];
        }
        obj = [obj retain]
        [instanceLock unlock];
        return [obj autorelease];
}

Your dealloc method will then look like this:

- (void)dealloc
{
        [instanceLock lock];
        if ([self retainCount] == 0)
        {
                sharedInstance = nil;
                // do cleanup
                [super dealloc];
        }
        [instanceLock unlock];
}

It's important that you check the retain count before freeing the singleton, 
because otherwise you might have one thread call -sharedInstance while another 
calls -release.  The +sharedInstance method will acquire the lock, blocking the 
-dealloc method in the other thread.  When the -dealloc method is entered, you 
have to check that you really should proceed with the deallocation.  Don't 
actually destroy the object unless no other thread has gained a reference to 
it.  

In general, as Richard says, you don't deallocate singletons.  They are 
expected to exist for the lifetime of the program.  The lazy-initialization 
trick just means that they don't really exist until observed; you can still 
reason about them as if they did exist from the program start (unless creation 
of them has side effects).  

>> By the way, where did you get the spaces-inside-square-brackets style
>> from?  I don't think I've ever seen Objective-C written like that.
> 
> I didn't get it anywhere, that's my own :)

Interesting.  What's the rationale for it?  It looks a bit more Smalltalk-like. 
 I can imagine it working quite nicely in an editor that does rainbow brackets.

David

-- Sent from my STANTEC-ZEBRA





reply via email to

[Prev in Thread] Current Thread [Next in Thread]