Apple은 ARC에서 싱글 톤 패턴을 구현하기 위해 dispatch_once를 사용하도록 권장하는 이유는 무엇입니까?


305

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

백그라운드에서 싱글 톤을 비동기 적으로 인스턴스화하는 것은 나쁜 생각이 아닙니까? 공유 인스턴스를 요청하고 즉시 의존하면 dispatch_once가 크리스마스까지 객체를 만들 때 어떻게됩니까? 바로 돌아 오지 않습니까? 적어도 그것은 그랜드 센트럴 파견의 요점 인 것 같습니다.

그들이 왜 이러는거야?


Note: static and global variables default to zero.
ikkentim

답변:


418

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()더 빠르다는 것입니다. 또한 같은 시간에 모두 시도하면 sharedInstance의 할당을 수행하는 여러 스레드로부터 사용자를 보호하기 때문에 의미 론적으로 깨끗합니다. 두 개의 인스턴스를 만들 수 없습니다. 전체 아이디어 dispatch_once()는 "한 번만 수행하고 한 번만 수행"하는 것입니다. 이것이 바로 우리가하는 일입니다.


4
논쟁을 위해 문서 가 동 기적으로 실행되고 있다고 말하지는 않습니다. 여러 개의 동시 호출이 직렬화 될 것입니다.
전문가

5
당신은 그것이 더 빠르다고 주장합니다-얼마나 빠릅니까? 나는 당신이 진실을 말하지 않는다고 생각할 이유가 없지만 간단한 벤치 마크를보고 싶습니다.
Joshua Gross

29
방금 간단한 벤치 마크를 수행했으며 (iPhone 5에서) dispatch_once가 @synchronized보다 약 2 배 빠릅니다.
Joshua Gross

3
@ReneDohan : 아무도 다른 스레드에서 해당 메소드를 호출하지 않는다는 것을 100 % 확신하면 작동합니다. 그러나 사용 dispatch_once()은 정말 간단합니다 (특히 Xcode는 그것을 자동으로 전체 코드 스 니펫으로 자동 완성하기 때문에) 메소드가 스레드 안전 해야하는지 여부를 고려할 필요조차 없습니다.
릴리 발라드

1
@ 시우 잉 : 사실, 그건 사실이 아닙니다. 먼저, +initialize공유 인스턴스를 만들려고하지 않더라도 수업이 시작되기 전에 수행 된 모든 작업이 수행됩니다 . 일반적으로 게으른 초기화 (필요할 때만 무언가 생성)가 더 좋습니다. 둘째, 성능 주장조차 사실이 아닙니다. 에서 dispatch_once()말하는 것과 거의 같은 시간이 걸립니다 . 이미가 있다면 공유 인스턴스를 만드는 것이 빠르지 만 대부분의 클래스는 그렇지 않습니다. if (self == [MyClass class])+initialize+initialize
릴리 발라드

41

한 번만 실행되기 때문입니다. 따라서 다른 스레드에서 두 번 액세스하려고하면 문제가 발생하지 않습니다.

Mike Ash는 싱글 톤 관리 및 피드 블로그 게시물에 전체 설명이 있습니다.

모든 GCD 블록이 비동기 적으로 실행되는 것은 아닙니다.


Lily 's가 더 나은 대답이지만 Mike Ash의 게시물에 대한 링크를 유지하기 위해 내 것을 떠나고 있습니다.
Abizern
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.