iOS的这个单例实现的任何潜在缺陷?

For*_*est 1 singleton objective-c ios

最直接和最简单的实现是这样的

static MySingleton *_instance = nil;

    + (MySingleton *) instance
{
    @synchronized (_instance)
    {
        if (_instance == nil)
        {
            _instance = [[MySingleton alloc] init];
        }

        return _instance;
    }
}
Run Code Online (Sandbox Code Playgroud)

实际上我知道几个关于单身的热门帖子,比如 在iOS中实现Singleton 和pop 模板

所以我的问题是"上述实施的任何缺陷"?

rob*_*off 5

是的,您的实施存在很大缺陷.该@synchronized指令变为调用objc_sync_enter和稍后调用objc_sync_exit.instance第一次调用方法时,_instancenil.objc_sync_enter如果通过它nil,该函数不会锁定,正如您可以通过查看其源代码看到的那样.

因此,如果两个线程在初始化instance之前同时调用_instance,则将创建两个实例MySingleton.

此外,您应该将_instance变量放在函数中,除非您有理由将其公开给整个源文件.

iOS 4.0及更高版本的单例访问器的首选实现使用非常高效的dispatch_once函数,如下所示:

+ (MySingleton *)sharedInstance {
    static MySingleton *theInstance;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        theInstance = [[self alloc] init];
    });
    return theInstance;
}
Run Code Online (Sandbox Code Playgroud)

dispatch_once功能在iOS 4.0之前不可用,因此如果您确实需要支持较旧的iOS版本(这不太可能),则必须使用效率较低的版本@synchronized.由于无法同步nil,因此可以在类对象上进行同步:

+ (MySingleton *)sharedInstance {
    static volatile MySingleton *theInstance;
    if (!theInstance) {
        @synchronized (self) {
            if (!theInstance)
                theInstance = [[self alloc] init];
        }
    }
    return theInstance;
}
Run Code Online (Sandbox Code Playgroud)