it-swarm.com.ru

Почему Apple рекомендует использовать dispatch_once для реализации одноэлементного шаблона в ARC?

Какова точная причина использования dispatch_once в средстве доступа к экземпляру единого экземпляра в ARC?

+ (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;
}

Разве это не плохая идея - создать экземпляр Singleton асинхронно в фоновом режиме? Я имею в виду, что произойдет, если я запрашиваю этот общий экземпляр и сразу полагаюсь на него, но dispatch_once требуется до Рождества для создания моего объекта? Не сразу возвращается, верно? По крайней мере, в этом и заключается весь смысл Grand Central Dispatch.

Так почему они это делают?

301
Proud Member

dispatch_once() абсолютно синхронный. Не все методы GCD делают вещи асинхронно (в данном случае dispatch_sync() синхронна). Использование dispatch_once() заменяет следующую идиому:

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

Преимущество dispatch_once() в этом заключается в том, что это быстрее. Это также семантически чище, потому что оно также защищает вас от нескольких потоков, выполняющих alloc init вашего sharedInstance - если они все пытаются в одно и то же время. Это не позволит создать два экземпляра. Вся идея dispatch_once() заключается в том, чтобы "выполнить что-то один раз и только один раз", и именно это мы и делаем.

414
Lily Ballard

Потому что он будет работать только один раз. Так что если вы попытаетесь получить к нему доступ дважды из разных потоков, это не вызовет проблем.

У Майка Эша есть полное описание в его Уход и кормление синглетонов пост в блоге.

Не все блоки GCD запускаются асинхронно.

41
Abizern