正确的单一模式目标C(iOS)?

bla*_*acx 29 singleton objective-c grand-central-dispatch ios

我在网上找到了一些信息来创建一个使用GCD的单例类.这很酷,因为它的线程安全,开销很低.遗憾的是,我找不到完整的解决方案,只能找到sharedInstance方法的片段.所以我使用试错法制作了自己的课 - 而且瞧瞧 - 以下内容出来了:

@implementation MySingleton

// MARK: -
// MARK: Singleton Pattern using GCD

+ (id)allocWithZone:(NSZone *)zone { return [[self sharedInstance] retain]; }
- (id)copyWithZone:(NSZone *)zone { return self; }
- (id)autorelease { return self; }
- (oneway void)release { /* Singletons can't be released */ }
- (void)dealloc { [super dealloc]; /* should never be called */ }
- (id)retain { return self; }
- (NSUInteger)retainCount { return NSUIntegerMax; /* That's soooo non-zero */ }

+ (MySingleton *)sharedInstance
{
    static MySingleton * instance = nil;

    static dispatch_once_t predicate;   
    dispatch_once(&predicate, ^{
        // --- call to super avoids a deadlock with the above allocWithZone
        instance = [[super allocWithZone:nil] init];
    });

    return instance;
}

// MARK: -
// MARK: Initialization

- (id)init
{
    self = [super init];
    if (self) 
    {
        // Initialization code here.
    }
    return self;
}

@end
Run Code Online (Sandbox Code Playgroud)

如果我遗漏了某些东西或做了一些完全错误的事情,请随时发表评论并告诉我;)

干杯斯蒂芬

bbu*_*bum 82

把事情简单化:

+(instancetype)sharedInstance
{
    static dispatch_once_t pred;
    static id sharedInstance = nil;
    dispatch_once(&pred, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (void)dealloc
{
    // implement -dealloc & remove abort() when refactoring for
    // non-singleton use.
    abort();
}
Run Code Online (Sandbox Code Playgroud)

这就对了.重写retain,release,retainCount和剩下的只是隐藏错误和加入一些不必要的行代码.每行代码都是等待发生的错误.实际上,如果要导致dealloc在共享实例上调用,则应用程序中存在非常严重的错误.那个bug应该修复,而不是隐藏.

这种方法也适用于重构以支持非单例使用模式.几乎所有存在于单个版本之后的单例最终都会被重构为非单例形式.一些(像NSFileManager)继续支持单例模式,同时也支持任意实例化.

请注意,上述内容在ARC中也"正常工作".

  • 单身人员从被请求到应用程序终止时就存在.它们不会被解除分配并重新实例化.由于没有理由在应用程序终止时解除分配任何内容,因此没有理由"释放"单例.因为单身人士的破坏不太可能被测试过,所以实施所谓的"dealloc"是一种纯粹的防御性措施,以提醒未来你过去没有考虑过这个类的内存管理. (5认同)

Jan*_*ano 19

// See Mike Ash "Care and Feeding of Singletons"
// See Cocoa Samurai "Singletons: You're doing them wrong"
+(MySingleton *)singleton {
    static dispatch_once_t pred;
    static MySingleton *shared = nil;
    dispatch_once(&pred, ^{
        shared = [[MySingleton alloc] init];
        shared.someIvar = @"blah";
    });
    return shared;
}
Run Code Online (Sandbox Code Playgroud)

请注意,dispatch_once不是可重入的,因此从dispatch_once块内部调用自身会使程序死锁.

不要试图对自己进行防御性编码.如果你没有编写框架代码,请将你的类视为正常,然后坚持上面的单例习语.把单身成语想象成一种方便的方法,而不是你班级的定义特征.您希望在单元测试期间将您的类视为普通类,因此可以保留可访问的构造函数.

不要打扰使用 allocWithZone:

  • 它忽略了它的论点并且表现得很像alloc.Objective-C中不再使用内存区域,因此allocWithZone:只保留与旧代码的兼容性.
  • 它不起作用.您无法在Objective-C中强制执行单例行为,因为始终可以使用NSAllocateObject()和创建更多实例class_createInstance().

单件工厂方法始终返回以下三种类型之一:

  • id 指示返回类型未完全知晓(您正在构建类集群的情况).
  • instancetype 表示返回的类型是封闭类的实例.
  • 类名本身(MySingleton在示例中)保持简单.

自从你标记了这个iOS以来,替换单例是将ivar保存到app委托,然后使用一个方便的宏,如果你改变主意你可以重新定义:

#define coreDataManager() \
        ((AppDelegate*)[[UIApplication sharedApplication] delegate]).coreDataManager
Run Code Online (Sandbox Code Playgroud)