ios 为什么Apple推荐使用dispatch_once来实现ARC下的单例模式?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9119042/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:39:49  来源:igfitidea点击:

Why does Apple recommend to use dispatch_once for implementing the singleton pattern under ARC?

iosobjective-csingletonautomatic-ref-counting

提问by Proud Member

What's the exact reason for using dispatch_once in the shared instance accessor of a singleton under ARC?

在 ARC 下单例的共享实例访问器中使用 dispatch_once 的确切原因是什么?

+ (MyClass *)sharedInstance
{
    //  Static local predicate must be initialized to 0
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[MyClass alloc] init];
        // Do any other initialisation stuff here
    });
    return sharedInstance;
}

Isn't it a bad idea to instantiate the singleton asynchronously in the background? I mean what happens if I request that shared instance and rely on it immediately, but dispatch_once takes until Christmas to create my object? It doesn't return immediately right? At least that seems to be the whole point of Grand Central Dispatch.

在后台异步实例化单例不是一个坏主意吗?我的意思是,如果我请求该共享实例并立即依赖它,但 dispatch_once 需要到圣诞节才能创建我的对象,会发生什么?它不会立即返回对吗?至少这似乎是 Grand Central Dispatch 的重点。

So why are they doing this?

那么他们为什么要这样做呢?

回答by Lily Ballard

dispatch_once()is absolutely synchronous. Not all GCD methods do things asynchronously (case in point, dispatch_sync()is synchronous). The use of dispatch_once()replaces the following idiom:

dispatch_once()是绝对同步的。并非所有 GCD 方法都是异步执行的(例如,dispatch_sync()是同步的)。的使用dispatch_once()取代了以下习语:

+ (MyClass *)sharedInstance {
    static MyClass *sharedInstance;
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[MyClass alloc] init];
        }
    }
    return sharedInstance;
}

The benefit of dispatch_once()over this is that it's faster. It's also semantically cleaner, because it also protects you from multiple threads doing alloc init of your sharedInstance--if they all try at the same exact time. It won't allow two instances to be created. The entire idea of dispatch_once()is "perform something once and only once", which is precisely what we're doing.

这样做的好处dispatch_once()是它更快。它在语义上也更清晰,因为它还可以保护您免受多个线程执行 sharedInstance 的 alloc init 的影响——如果它们都在同一时间尝试。它不允许创建两个实例。整个想法dispatch_once()是“执行一次且仅一次”,这正是我们正在做的。

回答by Abizern

Because it will only run once. So if you try and access it twice from different threads it won't cause a problem.

因为它只会运行一次。因此,如果您尝试从不同的线程访问它两次,它不会导致问题。

Mike Ash has a full description in his Care and Feeding of Singletonsblog post.

Mike Ash 在他对单身人士的关心和喂养博客文章中有完整的描述。

Not all GCD blocks are run asynchronously.

并非所有 GCD 块都是异步运行的。