开发者

Objective-C: static field and implementing singleton pattern

Good day, friends.

O开发者_运维问答nce again stupid question about Obj-C from newbie :)

I'm trying to implement singleton design pattern in Obj-C:

@interface SampleSingleton : NSObject {
@private
    static SampleSingleton* instance;
}
+(SampleSingleton*) getInstance;

Compiler returns error: "expected specifier-qualifier-list before 'static'".


Please find below the Objective-C code snippet I am using, for proper thread-safe singleton implementation

header file :

/*
 *
 * Singleton interface that match Cocoa recommendation
 * @ http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32
 * extended with thread-safe pattern
 */
@interface MyCustomManager : NSObject { 
}

#pragma mark Singleton Thred-Safe Pattern

+ (MyCustomManager *) sharedInstance;
+ (id)allocWithZone:(NSZone *)zone;
- (id)copyWithZone:(NSZone *)zone;
- (id)retain;
- (NSUInteger)retainCount;
- (void)release;
- (id)autorelease;

#pragma mark -

implementation file :

/*
 * My custom manager Class singleton implementation
 */
@implementation MyCustomManager

#pragma mark Initializers

/*
 * specific initialize goes here
 */
- (void) specificInitialize
{
    // ...
}

/*
 * Ensure any owned object is properly released
 */
- (void) dealloc
{
[super dealloc];
}

#pragma mark -

#pragma mark Singleton Thred-Safe Pattern

//- use Volatile to make sure we are not foiled by CPU caches
static void * volatile sharedInstance = nil;                                                

/*
 * retrieve sharedInstance based on OSAtomicCompareAndSwapPtrBarrier that 
 * acts as both a write barrier for the setting thread and a read barrier from the testing thread
 * more info @ http://stackoverflow.com/questions/145154/what-does-your-objective-c-singleton-look-like/2449664#2449664
 * and http://stackoverflow.com/questions/6915/thread-safe-lazy-contruction-of-a-singleton-in-c/6943#6943
 */
+ (MyCustomManager *) sharedInstance {  
    //- check sharedInstance existenz 
    while (!sharedInstance) {  
        //- create a temporary instance of the singleton    
        id temp = [super allocWithZone:NSDefaultMallocZone()];
        //- The OSAtomicCompareAndSwapPtrBarrier function provided on Mac OS X 
        //- checks whether sharedInstance is NULL and only actually sets it to temp to it if it is. 
        //- This uses hardware support to really, literally only perform the swap once and tell whether it happened.
        if(OSAtomicCompareAndSwapPtrBarrier(0x0, (void *)temp, &sharedInstance)) {
            //- compute singleton initialize
        MyCustomManager *singleton = (MyCustomManager *) sharedInstance;
            [singleton specificInitialize];
        }
        else {
            //- if the swap didn't take place, delete the temporary instance
            [temp release]; 
            temp = nil;
        }                                                                                                 
    }   
    //- return computed sharedInstance
    return sharedInstance;                                                                        
}

/*
 * method to ensure that another instance is not allocated if someone tries to allocate 
 * and initialize an instance of your class directly instead of using the class factory method. 
 * Instead, it just returns the shared object.
 */
+ (id)allocWithZone:(NSZone *)zone
{
    return [[self sharedInstance] retain];
}

/*
 * Implements the base protocol methods to do the appropriate things to ensure singleton     status. 
 * Applies to memory-managed code, not to garbage-collected code
 */
- (id)copyWithZone:(NSZone *)zone
{
    return self;
}

/*
 * Implements the base protocol methods to do the appropriate things to ensure singleton status. 
 * Applies to memory-managed code, not to garbage-collected code
 */
- (id)retain
{
    return self;
}

/*
 * Implements the base protocol methods to do the appropriate things to ensure singleton status. 
 * Applies to memory-managed code, not to garbage-collected code
 */
- (NSUInteger)retainCount
{
    return NSUIntegerMax;  //denotes an object that cannot be released
}

/*
 * Implements the base protocol methods to do the appropriate things to ensure singleton status. 
 * Applies to memory-managed code, not to garbage-collected code
 */
- (void)release
{
    //do nothing
}

/*
 * Implements the base protocol methods to do the appropriate things to ensure singleton status. 
 * Applies to memory-managed code, not to garbage-collected code
 */
- (id)autorelease
{
    return self;
}

#pragma mark -

Just to help you starting in objective-c and not get lost in your project structure, you can consider having the project structure matching your file system so as your project becomes bigger you won't get lost.

Also please consider using a proper class naming convention, and stick to it.

I a providing you mine as sample:

  • Any class that match singleton pattern is named using Manager suffix (E.g. MyCustomManager ).

  • Any static class is named using Helper suffix (E.g. MyCustomHelper).

  • 
Any class dedicated to control particular process is named using Controller suffix ( E.g. MyParticularTaskConstroller ).


  • Any UI control that inherit from another control needs provide control suffix ( E.g. MyCustomDetailCell inheriting from UITableViewCell )

Hope this helps.


You can't use static inside a class interface declaration. The singleton should be declared as a static stand alone variable in the .m file. I normally do this (if I feel I can't avoid having a singleton):

@interface SampleSingleton : NSObject 
{
@private
}

+(SampleSingleton*) theSingleton;

@end

// .m file 

@implementation SampleSingleton

+(SampleSingleton*) theSingleton
{
    static SampleSingleton* theSingleton = nil;

    if (theSingleton  == nil)
    {
        theSingleton = [[SampleSingleton alloc] init];
    }
    return theSingleton;
}


Please check out my question here and the wonderful answer by Nick DeMoore (with lots of comments and code fixes). Having a singleton that you can wire up in IB (well, whatever you call it in XCode 4) is really helpful.

The cool thing is that you can use the same Singleton and wire some of its outlets in one NIB, and some of its outlets in another... since it's really a singleton, there can be only one instance in the entire runtime system. Works amazingly well.

Note: Every time you use Singleton people will say it's a bad idea.


The static SampleSingleton* instance; line can't go in the @interface section. Most people put it above.

Objective-c doesn't really lend itself to the singleton pattern as well as some other languages. However there are a bunch of different implementations to look at in this question.

Some people argue that Singleton is not a great pattern at all, and I'm trying to wean myself off using it - but that's my choice.


This is how I usually implement a singleton method

+(SampleSingleton * )sampleSingleton
{
    static SampleSingleton   * theSampleSingleton = nil;
    if( theSampleSingleton == nil )
        theSampleSingleton = [[SampleSingleton alloc] init];
    return theSampleSingleton;
}

to make this thread safe you would do

+(SampleSingleton * )sampleSingleton
{
    static SampleSingleton   * theSampleSingleton = nil;
    if( theSampleSingleton == nil )
    {
        @syncronise([SampleSingleton class])
        {
            if( theSampleSingleton == nil )
                theSampleSingleton = [[SampleSingleton alloc] init];
        }
    }
    return theSampleSingleton;
}

also instead of using a singleton, you already have a singleton in the form of the UIApplicationDelegate, you could always add a method to you delegate to get your SampleSingleton from your delegate.

Another point to consider about singletons is it really necessary to enforce singletons, UIApplication has a sharedApplication which performs the function of creating a singleton, but there is nothing really stopping you from creating a new instance.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜