2010-03-09 78 views
3

我正在寻找单身人士,我很好奇正确的方式来做的alloc,从看文档,书籍&网络似乎有几个使用的方法。正确的方式来分配共享实例(单身人士)?

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 *sharedReactor = nil; 
+(ReactorClass *)sharedInstance { 
    if(sharedReactor == nil) { 
     sharedReactor == [[[self class] alloc] init]; 
    } 
    return sharedReactor; 
} 

许多感谢...

加里

回答

2

在这种情况下使用[self class]实际上是一种浪费 - 除非您涉及子类,否则M1和M3并没有真正的不同,实际情况是其余的实现不符合它。

考虑,如果你创建ReactorClass的这样的一个子类,会发生什么:

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

如果你调用[MyReactorClass sharedInstance]你可以看到,从单一的静态变量sharedReactor其读数。这就好,如果你只创建一个子类,但你需要非常清楚这一点,并且你调用的任何第三方库都不会为它们创建的单例使用相同的基类,但你不知道。如果像Mark建议的那样,将M3代码复制到你的子类中,它会更好地工作,但是你需要问自己“为什么我要这样做?” - 你没有什么好处,完全可以编写代码,而不是依赖超类的实现细节。

为了做到这一点,你需要保留一个静态字典(在基类的初始化过程中创建),并将条目插入到您正在创建的单例的实际类中。

担心是否重写alloc或allocWithZone:再次是子类化的事情,但实际上,任何从singleton超类继承并随后使用其分配方法的人都应该得到不良行为。如果你想编写完美的单例基类,你应该创建和DOCUMENT被调用的其他方法,这样子类可以解决他们可能想到的任何问题,而不会干扰你的基础结构。

就个人而言,我的单身抛出异常出所有方法开始init和做他们真正的初​​始化在未知方法(确定,它被称为_init) - 它保证人们滥用单例类没有得到意外的行为。

这真的归结为“你相信你的子分类器多少钱”。如果你认为他是个傻瓜,你需要重写诸如释放,保留等等的东西。如果你认为他遵循了内存管理规则,那么你可以将这些东西放在一边,因为它们只会起作用。在他们的示例代码中,Apple在这方面确实有点愚蠢;他们有点偏执,但远不能防蠢。

1

如果你把M3在ReactorClass的实现,那么它是一样的M1分配和返回ReactorClass。然而,M3可以放入ReactorClass的子类的实现中,然后返回一个指向该子类的对象的指针。

M2总是返回它是在执行超

3

我倾向于他们这样写:

+ (id)sharedFoo 
{ 
    static Foo *_sharedFoo; 

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

    return _sharedFoo; 
} 

但是,请注意,上面的代码不是线程安全的。如果您需要一个线程安全的实现,Chris Hanson has a good suggestion,它将在+initialize的重写实现中创建实例。

+0

+1 for + initialize implementation – 2010-03-09 22:38:10