正确的方式来分配共享实例(单例)?

时间:2010-03-09 14:44:52

标签: iphone objective-c

我正在寻找单身人士,我很好奇正确的方式来做分配,从查看文档,书籍和网上似乎有一些使用方法。

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;
}
非常感谢...

加里

3 个答案:

答案 0 :(得分:3)

我倾向于这样写:

+ (id)sharedFoo
{
    static Foo *_sharedFoo;

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

    return _sharedFoo;
}

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

答案 1 :(得分:2)

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

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

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

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

要正确地执行此操作,您将保留一个静态字典(在基类的+初始化期间创建),并将条目插入到由您创建的单例的实际类键入的字段中。

担心是否覆盖alloc或allocWithZone:再次是一个子类化的东西,但实际上,任何从单例超类继承然后用它的分配方法搞砸的人都应该得到它们的不良行为。如果你想编写完美的单例基类,你应该创建和记录被调用的其他方法,以便子类可以解决他们可能想到的任何问题,而不会弄乱你的基础设施。

就我个人而言,我的单身人士从init开始从所有方法中抛出异常并以未知方法进行真正的初始化(好吧,它被称为_init) - 保证人们滥用单身人士类别得到意想不到的行为。

它真的归结为“你相信你的子程序有多少”。如果你认为他是一个白痴,你需要覆盖释放,保留等等。如果你认为他遵循了内存管理规则,你可以把这些东西留下来,因为它们只会起作用。在他们的示例代码中,Apple在这方面确实有点愚蠢;他们有些偏执,但远没有白痴。

答案 2 :(得分:1)

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

M2总是返回它所在的实现的超类。