6

Moje pytanie jest bardzo podobny do tego: Use Singleton In Interface Builder?Singleton w konstruktorze Interface z ARC

Jedyną różnicą jest to, że używam ARC. Tak więc, jeśli uproszczone, mój Singleton wygląda tak:

Manager.m

@implementation Manager 

+ (instancetype)sharedManager { 
    __strong static id sharedInstance = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     sharedInstance = [[self alloc] init]; 
    }); 
    return sharedInstance; 
} 

@end 

Więc pytanie brzmi, czy jest to możliwe do przyjęcia go do interfejsu Builder nadal będąc z ARC?

Oczywiście rozumiem, że prostsze może być przepisanie tej klasy bez ARC, więc pytanie jest raczej akademickie. :)

+0

W jaki sposób pojawia się Interface Builder? Jak to jest powiązane? Co jest nie tak z twoim aktualnym kodem? –

+0

Służy do wiązania kontroli w IB. – Ievgen

Odpowiedz

10

Gdy stalówka jest niezarchiwizowane, będzie to próba albo alloc/init lub alloc/initWithCoder: nowa instancja klasy.

Więc, co można zrobić, to przechwytujący tej rozmowy i przekierowują go do powrotu swoje pojedyncza:

+ (id)sharedInstance { 
    static Singleton *sharedInstance = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
    sharedInstance = [[self actualAlloc] actualInit]; 
    }); 
    return sharedInstance; 
} 

+ (id)actualAlloc { 
    return [super alloc]; 
} 

+ (id)alloc { 
    return [Singleton sharedInstance]; 
} 

- (id)actualInit { 
    self = [super init]; 
    if (self) { 
    // singleton setup... 
    } 
    return self; 
} 

- (id)init { 
    return self; 
} 

- (id)initWithCoder:(NSCoder *)decoder { 
    return self; 
} 

Pozwala -init i -initWithCoder: być bezpiecznie zwany kilka razy na tym samym obiekcie. Generalnie nie zaleca się, aby na to zezwolić, ale biorąc pod uwagę, że singletony są już przypadkami "miejsca, w którym rzeczy mogą się naprawdę niewiarygodnie", nie jest to najgorsze, co możesz zrobić.

+1

Zgadza się. Ale mówiłem o ARC. Który nie pozwala tej sztuczce '[[Singleton sharedInstance] zachować]' – Ievgen

+0

@Eugene, a następnie wyjąć wywołanie 'keep '. –

+0

Nadal nie podążam. Jeśli wyjmę "zatrzymaj" - mój singleton zostanie zwolniony, gdy IB będzie z nim skończyć. – Ievgen

3

Aby być kompletnym, oto implementacja Singleton, która może być używana z poziomu Kreatora interfejsu. Różnica polega na metodzie actualAlloc. Ponieważ [super alloc] nadal będzie wywoływać [self allocWithZone:] - nie przydzieli obiektu.

Singleton.h

@interface Singleton : NSObject 

+ (instancetype)sharedInstance; 

@end 

Singleton.m

@implementation Singleton 

+ (instancetype)sharedInstance { 
    __strong static id _sharedInstance = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     _sharedInstance = [[self _alloc] _init]; 
    }); 
    return _sharedInstance; 
} 

+ (id)allocWithZone:(NSZone *)zone { 
    return [self sharedInstance]; 
} 

+ (id)alloc { 
    return [self sharedInstance]; 
} 

- (id)init { 
    return self; 
} 

+ (id)_alloc { 
    return [super allocWithZone:NULL]; //this is important, because otherwise the object wouldn't be allocated 
} 

- (id)_init { 
    return [super init]; 
} 

@end 
+0

Dla wszystkich (głównie moich) korzyści ... I [stworzył tylko nieznacznie zmodyfikowany Gist] (https://gist.github.com/mralexgray/6891945) z tego. Czemu? Ponieważ to JEDYNĄ rzecz, która działa. –

0

@Eugene z iOS doc planie "Ze względów historycznych, alloc wywołuje allocWithZone:.", Więc istnieje nie ma potrzeby ponownego stosowania metody alloc.