Objective-C:静态字段和实现单例模式

时间:2011-08-02 13:16:58

标签: objective-c singleton constants

美好的一天,朋友们。

再一次关于来自新手的Obj-C的愚蠢问题:)

我正在尝试在Obj-C中实现单例设计模式:

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

编译器返回错误:“在'静态'之前预期的说明符 - 限定符 - 列表”。

5 个答案:

答案 0 :(得分:8)

您不能在类接口声明中使用static。单例应该在.m文件中声明为静态独立变量。我通常这样做(如果我觉得我不能避免单身):

@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;
}

答案 1 :(得分:8)

请在下面找到我正在使用的Objective-C代码片段,以获得正确的线程安全单例实现

头文件:

/*
 *
 * 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 -

实施档案:

/*
 * 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 -

只是为了帮助你从objective-c开始而不是迷失在你的项目结构中,你可以考虑让项目结构与你的文件系统相匹配,这样你的项目就会变得更大,你不会迷路。

另外请考虑使用适当的类命名约定,并坚持使用它。

我向你提供我的样本:

  • 任何匹配单例模式的类都是使用Manager后缀(例如MyCustomManager)命名的。

  • 使用Helper后缀(例如MyCustomHelper)命名任何静态类。

  • 任何专门用于控制特定进程的类都使用Controller后缀(例如MyParticularTaskConstroller)命名。

  • 从其他控件继承的任何UI控件都需要提供控件后缀(例如,继承自UITableViewCell的MyCustomDetailCell)

希望这有帮助。

答案 2 :(得分:1)

请查看我的问题here以及Nick DeMoore的精彩答案(包含大量注释和代码修复)。拥有一个可以在IB中连接的单例(好吧,无论你在XCode 4中调用它)都非常有用。

很酷的是你可以使用相同的Singleton并在一个NIB中连接它的一些插座,而在另一个NIB中连接它的一些插座......因为它实际上是一个单独的,所以在整个运行时只能有一个实例系统。效果非常好。

注意:每次使用Singleton时,人们会说这是一个坏主意。

答案 3 :(得分:0)

静态SampleSingleton* instance;行无法进入@interface部分。大多数人都把它放在上面。

Objective-c并不适用于单例模式以及其他一些语言。但是,在this question中可以看到许多不同的实现。

有些人认为Singleton根本不是一个很好的模式,我试图让自己不再使用它 - 但这是我的选择。

答案 4 :(得分:0)

这就是我通常实现单例方法的方法

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

要使这个线程安全,你会做

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

也不是使用单例,而是已经有了UIApplicationDelegate形式的单例,你总是可以添加一个方法来委托你从你的委托中获取你的SampleSingleton。

关于单身人士的另一个要点是强制执行单身人士是非常必要的,UIApplication有一个执行创建单身人士功能的共享应用程序,但没有什么可以阻止你创建一个新实例。