开发者

Correct way to alloc shared instance (singleton)?

I am looking at singletons and I was curious about the correct way to do the alloc, from looking at the docs, books & web there seems to be a few few methods in use.

M1:

static ReactorClass *sharedReactor = nil;
+(ReactorClass *)sharedInstance {
    if(sharedReactor == nil) {
        sharedReactor == [[ReactorClass alloc] init];
    }
    return sharedReactor;
}

M2:

static ReactorClass *sharedReactor = nil;
+(ReactorClass *)sharedInstance {
    if(sharedReactor == nil) {
        sharedReactor == [[super allocWithZone:NULL] init];
    }
    return sharedReactor;
}

M3:

static ReactorClass *shared开发者_StackOverflowReactor = nil;
+(ReactorClass *)sharedInstance {
    if(sharedReactor == nil) {
        sharedReactor == [[[self class] alloc] init];
    }
    return sharedReactor;
}

many thanks ...

gary


I tend to write them like this:

+ (id)sharedFoo
{
    static Foo *_sharedFoo;

    if (_sharedFoo == nil)
    {
        _sharedFoo = [[self alloc] init];
    }

    return _sharedFoo;
}

but, be aware that the above code is not thread-safe. If you need a thread-safe implementation, Chris Hanson has a good suggestion, which is to create the instance in an overridden implementation of +initialize.


Using [self class] is really a waste in this case - M1 and M3 aren't really that different unless you have subclasses involved, and the reality is that the rest of the implementation isn't up to it.

Consider what happens if you create a subclass of ReactorClass like this:

@interface MyReactorClass : ReactorClass {}
@end
@implementation MyReactorClass
@end

If you call [MyReactorClass sharedInstance] you can see that its reading from a single static variable sharedReactor. Thats ok if you only create one subclass but you need to be very conscious of that, and the fact that any 3rd party libraries you call don't also use the same base class for the singletons they create but you don't know about. If, as Mark suggested, you copy the M3 code into your subclass, it will work better but you need to ask yourself "why did I subclass this?" - you got little benefit and would have been better off coding it completely, instead of relying on the implementation details of the superclass.

To do it properly, you'd keep a static dictionary (create during the +initialise of the base class), and insert entries into it keyed by the actual class of the singleton you were creating.

Worrying about whether to override alloc or allocWithZone: is again a subclassing thing but really, anyone who inherits from a singleton superclass and then screws around with its allocation methods deserves the bad behaviour they get. If you want to code the perfect singleton base class, you should create and DOCUMENT additional methods that get called so that subclassers can solve any problem they might think of without messing with your infrastructure.

Personally, my singletons throw exceptions out of all methods starting with init and do their real initialisation in an unknown method (ok, its called _init) - that GUARANTEES that people misusing the singleton class don't get unexpected behaviour.

It really boils down to "how much do you trust your subclasser". If you assume he's an idiot, you need to override things like release, retain, etc. If you assume he follows the memory management rules, you can leave those things alone because they'll just work. Apple are really a bit stupid in this regard in their sample code; they are somewhat paranoid but nowhere near idiot-proof.


If you put M3 in the implementation of ReactorClass then it is the same as M1 allocating and returning a ReactorClass. However M3 can if put in the implementation of a subclass of ReactorClass then will return a pointer to an object of that subclass.

M2 always returns the superclass of the implementation it is in.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜