Apple Singleton示例查询?

时间:2010-03-09 16:52:48

标签: iphone objective-c cocoa

我对这段代码(在CocoaFundamentals指南中提供)有点困惑,它在创建单例实例时会覆盖一些方法。

static id sharedReactor = nil;

+(id)sharedInstance {
    if(sharedReactor == nil) sharedReactor = [[super allocWithZone:NULL] init];
    return sharedReactor;
}

+(id)allocWithZone:(NSZone *)zone {
    return[[self sharedInstance] retain];
}

-(id)retain {
    return self;
}

在创建单例实例的代码中,+ sharedInstance方法从超类(在我的例子中是NSObject)中调用[super allocWithZone:NILL]上面的allocWithZone仅在您尝试使用它创建新的时调用单。

我感到困惑的是使用retain,尤其是看到retain也被覆盖以返回self。任何人都可以解释这个,不能写出来:

+(id)allocWithZone:(NSZone *)zone {
    return [self sharedInstance];
}

-(id)retain {
    return self;
}

EDIT_001:

根据评论和阅读网上的各种帖子,我决定采用以下内容(见下文)我选择采用共享单例方法,如果需要,我可以选择创建第二个或第三个实例。同样在这个阶段,因为我只使用单例作为MVC的模型部分用于简单的iPhone应用程序,所以我决定将线程安全性排除在外。我知道它很重要,随着我越来越熟悉iPhone编程,我可能会使用+ initialize(记住它可以被调用两次的子类问题)另外我添加了一个dealloc,首先要记录一条消息应该是单例被释放,但如果不再需要单身人士,也要妥善清理。

@interface SharedManager : NSObject
+(id)sharedInstance;
@end

@implementation SharedManager

static id myInstance = nil;

+(id)sharedInstance {
    if(myInstance == nil) {
        myInstance = [[self alloc] init];
    }
    return myInstance;
}

-(void)dealloc {
    NSLog(@"_deal: %@", [self class]);
    [super dealloc];
    myInstance = nil;
}
@end

在测试中,我发现我在dealloc中将静态变量设置为nil,或者它保持了指向原始对象的指针。我最初对此感到有点困惑,因为我期望静态的范围是实例,我想它是类,而这是有道理的。

欢呼加里

2 个答案:

答案 0 :(得分:5)

首先,不要使用此代码。几乎没有理由为一个简单的单身人士做这一切。 Apple正在展示一个“强迫单身人士”,因为它不可能创造出两个。真的很需要这个。您几乎总是可以使用大多数具有单例构造函数的Cocoa对象使用的“共享单例”方法。

这是我实现共享单例的首选方式:

+ (MYManager *)sharedManager
{
    static MYManager *sharedManager = nil;
    if (sharedManager == nil)
    {
        sharedManager = [[self alloc] init];
    }
    return sharedManager;
}

就是这样。不需要其他代码。使用+sharedManager的呼叫者将获得共享实例。呼叫+alloc的呼叫者可以创建唯一的实例,如果他们真的想要。这就是像NSNotificationCenter这样着名的“单身人士”的作用。如果您真的想要自己的私人通知中心,那么该课程没有理由禁止它。这种方法具有以下优点:

  • 少量代码。
  • 在非共享实例有用的情况下更灵活。
  • 最重要的是:代码完成它所说的功能。认为他正在使用+alloc创建一个独特实例的调用者不会遇到令人惊讶的“远距离幽灵行为”行为,这需要他知道对象的内部实现细节。

如果你真的需要一个强制单身,因为有问题的对象映射到一个无法共享的独特资源(并且很少遇到这种情况),那么你仍然不应该使用+alloc诡计来强制执行它。这只是掩盖了尝试创建新实例的编程错误。相反,您应该以这种方式捕获编程错误:

+ (MYManager *)sharedManager
{
    static MYManager *sharedManager = nil;
    if (sharedManager == nil)
    {
        sharedManager = [[self alloc] initSharedManager];
    }
    return sharedManager;
}

- (id)init
{
    NSAssert(NO, @"Attempting to instantiate new instance. Use +sharedManager.");
    return nil;
}

// Private method. Obviously don't put this in your .h
- (id)initSharedManager
{
    self = [super init];
    ....
    return self;
}

答案 1 :(得分:3)

有一个很好的例子,不同的单例方法在SO上有注释: What does your Objective-C singleton look like?

如果有帮助,该示例对allocWithZone采用不同的方法:返回nil。

相关问题