Objective-C中的单例类严格实现

时间:2013-12-27 11:05:23

标签: objective-c cocoa singleton

我正在尝试创建一个单例类。在搜索相关文档时,我遇到了Apple Document,它严格执行单例。我在哪里找到了以下代码:

+ (MyGizmoClass*)sharedManager
{
    if (sharedGizmoManager == nil) {
        sharedGizmoManager = [[super allocWithZone:NULL] init];
    }
    return sharedGizmoManager;
}

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

任何人都可以告诉我,为什么有必要拨打+allocWithZone:?为什么调用+alloc会导致崩溃?

我们也覆盖了+allocWithZone:。为什么这样?为什么我们不能覆盖+alloc

提前致谢。

4 个答案:

答案 0 :(得分:2)

您引用的文档非常陈旧。打开它时会发出警告:

  

退休文件

     

重要提示:本文档可能并不代表当前开发的最佳做法。下载和其他资源的链接可能不再有效。

恕我直言,现在这种单身人士的实施是最好的选择:https://github.com/NYTimes/objective-c-style-guide#singletons

答案 1 :(得分:0)

  

当一个对象创建另一个对象时,有时候做一个好主意   确定它们都是从同一个记忆区域分配的。区域   方法(在NSObject协议中声明)可用于此   目的;它返回接收者所在的区域。

正如 BBum 所说:

  但实际情况是,几乎没有任何东西使用区域。它是   原本打算给予共同定位所有人的能力   与区域中的文档相关的对象,然后通过批量销毁它们   只需解除分配区域。在实践中,这被证明是行不通的   在OpenStep API中,十多年来一直没有使用这些区域。

同样在NSObject的Apple文档中:

  

此方法存在历史原因;内存区域不再存在   由Objective-C使用。

截至目前,我们使用这些来使用alloc创建单例类。

@interface SomeManager : NSObject
    + (MyObject *)singleton;
@end
@implementation SomeManager
    + (MyObject *)singleton {    
         static id singleton = nil; 
         @synchronized([MyObject class]){ 
              if (singleton == nil) { 
                  singleton = [[self alloc] init]; 
              } 
          }
          return singleton;
        }
 @end

答案 2 :(得分:0)

作为严格的单例,可以从不调用类的initnew,否则将发生编译时错误。我使用NS_UNAVAILABLE来完全隐藏initnew

NS_ASSUME_NONNULL_BEGIN
@interface My: NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
+ (instancetype)shared;

@property(nonatomic, assign) NSInteger i;
@end

NS_ASSUME_NONNULL_END

和实施文件:

@implementation My
- (instancetype)initPrivate {
    self = [super init];
    if (self) {
        // Do initialization
    }
    return self;
}

+ (instancetype)shared {
    static id _i = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _i = [[My alloc] initPrivate];
    });
    return _i;
}
@end

这时,initnew将触发编译时错误

My *m = My.new; // Error
My *m1 = [[My alloc] init]; // Error
My.shared.i = 6; // OK

答案 3 :(得分:-1)

似乎doc有点过时了。 目前的常见做法是使用GDC

+ (MyGizmoClass *)sharedInstance {
    static MyGizmoClass *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[MyGizmoClass alloc] init];
    });
    return instance;
}