Apple Singleton示例查询?

fuz*_*oat 1 iphone cocoa objective-c

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

static id sharedReactor = nil;

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

.

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

-(id)retain {
    return self;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

-(id)retain {
    return self;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

欢呼加里

Rob*_*ier 5

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

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

+ (MYManager *)sharedManager
{
    static MYManager *sharedManager = nil;
    if (sharedManager == nil)
    {
        sharedManager = [[self alloc] init];
    }
    return sharedManager;
}
Run Code Online (Sandbox Code Playgroud)

而已.不需要其他代码.使用的呼叫者+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;
}
Run Code Online (Sandbox Code Playgroud)