Objective c 目标C:静态场和实现单例模式

Objective c 目标C:静态场和实现单例模式,objective-c,singleton,constants,Objective C,Singleton,Constants,朋友们,你好 又一个关于Obj-C的愚蠢问题来自新手:) 我试图在Obj-C中实现单例设计模式: @interface SampleSingleton : NSObject { @private static SampleSingleton* instance; } +(SampleSingleton*) getInstance; 编译器返回错误:“预期的说明符限定符列表位于“static”之前。”staticSampleSingleton*实例行不能进入@界面部分。大多数人把它放在上

朋友们,你好

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

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

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

编译器返回错误:“预期的说明符限定符列表位于“static”之前。”

static
SampleSingleton*实例行不能进入
@界面
部分。大多数人把它放在上面

Objective-c并不像其他一些语言那样适用于单例模式。然而,在中有许多不同的实现


有些人认为单例模式根本不是一个好模式,我正试图放弃使用它——但这是我的选择。

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


请查看我的问题和Nick DeMoore的精彩答案(有很多评论和代码修复)。有一个可以在IB中连接的单例(好吧,不管你在XCode 4中如何称呼它)真的很有帮助

很酷的一点是,你可以使用同一个单件,把它的一些插座连接到一个笔尖上,把它的一些插座连接到另一个笔尖上。。。因为它实际上是一个单实例,所以在整个运行时系统中只能有一个实例。效果惊人地好


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

我通常就是这样实现Singleton方法的

+(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;
}
另外,您已经有了UIApplicationLegate形式的单例,而不是使用单例,您可以始终向委托添加一个方法,以从委托中获取SampleSingleton


另一个要考虑的问题是,它确实需要强制执行单独的任务,UIApple有一个共享应用程序,它执行创建一个单独的函数,但是没有什么真正阻止你创建一个新的实例。

< p>请在下面使用我正在使用的ObjuleC代码片段。用于正确的线程安全单例实现

头文件:

/*
 *
 * 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 -
<> >为了帮助你开始ObjuleC而不丢失你的项目结构,你可以考虑让项目结构与你的文件系统相匹配,这样你的项目就越大,你就不会迷路了。

也请考虑使用适当的类命名约定,并坚持它。 我向您提供我的样品:

  • 任何匹配单例模式的类都使用管理器后缀命名(例如MyCustomManager)

  • 任何静态类都使用助手后缀命名(例如MyCustomHelper)

  • 
任何专用于控制特定过程的类都使用控制器后缀命名(例如MySpecificularTaskController)。


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


希望这有帮助。

恐怕您的同步版本已损坏。您必须删除nil的外部测试。其中一个原因是优化编译器将在第一次测试中将SampleSingleton加载到寄存器中,并在同步块内的第二次测试中将使用相同的寄存器副本。还有其他更微妙的理由不使用它。谷歌“双重检查锁定”。我认为同步块可以防止这种情况,谢谢,我将不得不求助于原子函数。将volatile添加到singleton变量可以解决问题。可能不是因为除了我提到的问题外,还存在指向的对象的缓存一致性问题。i、 即使指针是正确的,对象的主体也可能没有从运行init代码的处理器的缓存中刷新出来。最好是删除外部测试并接受性能影响。我明白了,你说你必须以某种方式声明对象的全部内容也是易变的。我不认为singleton是个坏主意,我只是认为大多数时候不需要编写大量代码来执行它们,在Cocoa中,你可以看到[NSApplication sharedApplication]、[NSNotificationCenter defaultCenter]、[NSFileManager defaultManager]等基本上都是单例的,它们不会试图用init方法做任何复杂的事情。@Nathan Day,这是个好主意,但我的问题是想将IBOutlets连接到singleton对象。这起到了中心查找的作用,本质上。。。我已经(反复)被告知应该使用依赖项注入等,但我喜欢保持方法签名中没有重复出现的参数。不管怎么说,这里的评论已经广泛地涵盖了这一切:我无法理解a=nil;如果(a==nil){}@DavidOhanyan,则变量在函数内声明为静态。这意味着它与在函数外部声明静态变量完全相同,唯一的区别是它只在函数内部可见。它在程序启动时进行初始化,然后第一次通过函数分配对象引用,此后它不是零,因此它会保留该对象引用,直到程序退出。这个解决方案似乎是OSX的特定平台,因为我无法在iOS上使用它。在iOS上你会如何做同样的事情?@ArtOfWarfare:我在iOS 4上使用它没有任何问题,但它可能会受到iOS5 ARC(自动引用计数)引入的影响。如果您正在使用ARC,您可能会尝试通过查看上面的答案是否仍然可以安全地用于iOS 6/7来禁用此特定类的ARC?@Irshad Mohamed:无法为您提供最终答案,因为我从v4开始就没有在iOS上工作过。但可以肯定的是,如果您使用的是ARC imp,则不可能实现
/*
 * 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 -