关于iOS:为什么Apple建议使用dispatch_once在ARC下实现单例singleton模式?

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

在arc下的singleton的共享实例访问器中使用dispatch-once的确切原因是什么?

1
2
3
4
5
6
7
8
9
10
11
+ (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;
}

在后台异步实例化单例不是个坏主意吗?我的意思是,如果我请求共享实例并立即依赖它,但在圣诞节之前调度一次来创建我的对象会发生什么?它不会立即返回,对吗?至少,这似乎是大中央调度的全部要点。

那他们为什么要这样做?


dispatch_once()是绝对同步的。并非所有的gcd方法都是异步的(例如,dispatch_sync()是同步的)。使用dispatch_once()替代了以下习惯用法:

1
2
3
4
5
6
7
8
9
+ (MyClass *)sharedInstance {
    static MyClass *sharedInstance;
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[MyClass alloc] init];
        }
    }
    return sharedInstance;
}

dispatch_once()的好处在于它更快。它在语义上也更清晰,因为它还可以防止多个线程执行sharedinstance的alloc init——如果它们同时尝试的话。它不允许创建两个实例。dispatch_once()的全部思想是"做一次,而且只做一次",这正是我们正在做的。


因为它只能运行一次。所以,如果您尝试从不同的线程访问它两次,就不会产生问题。

MikeAsh在他护理和喂养单身汉的博客帖子中有一个完整的描述。

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