Jaki jest dokładny powód użycia dispatch_once we współużytkowanym instancie dla singletona pod 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;
}
Czy nie jest złym pomysłem asynchroniczne tworzenie singletonu w tle? Mam na myśli to, co się stanie, jeśli zażądam udostępnionego wystąpienia i natychmiast na nim polegam, ale dispatch_once trwa do świąt Bożego Narodzenia, aby utworzyć mój obiekt? Nie wraca natychmiast, prawda? Przynajmniej wydaje się, że o to właśnie chodzi w Grand Central Dispatch.
Dlaczego to robią?
ios
objective-c
singleton
automatic-ref-counting
Dumny członek
źródło
źródło
Note: static and global variables default to zero.
Odpowiedzi:
dispatch_once()
jest absolutnie synchroniczny. Nie wszystkie metody GCD działają asynchronicznie (przypadekdispatch_sync()
jest synchroniczny). Zastosowaniedispatch_once()
zastępuje następujący idiom:Zaletą
dispatch_once()
tego jest to, że jest szybszy. Jest również semantycznie czystszy, ponieważ chroni również przed wieloma wątkami wykonującymi alokację init z SharedInstance - jeśli wszystkie próbują w tym samym czasie. Nie pozwoli na utworzenie dwóch instancji. Cała ideadispatch_once()
polega na „wykonywaniu czegoś raz i tylko raz”, co właśnie robimy.źródło
dispatch_once()
jest bardzo proste (zwłaszcza, że Xcode będzie nawet automatycznie uzupełniał go do pełnego fragmentu kodu) i oznacza, że nigdy nie musisz zastanawiać się, czy metoda musi być bezpieczna dla wątków.+initialize
dzieje, dzieje się przed dotknięciem klasy, nawet jeśli nie próbujesz jeszcze utworzyć współużytkowanej instancji. Ogólnie rzecz biorąc, leniwa inicjalizacja (tworzenie czegoś tylko w razie potrzeby) jest lepsza. Po drugie, nawet twoje twierdzenie o wydajności nie jest prawdziwe.dispatch_once()
zajmuje prawie dokładnie taką samą ilość czasu jak mówiąif (self == [MyClass class])
w+initialize
. Jeśli masz już+initialize
, to tak, tworzenie współużytkowanej instancji jest szybsze, ale większość klas nie.Ponieważ będzie działać tylko raz. Więc jeśli spróbujesz uzyskać do niego dostęp dwa razy z różnych wątków, nie spowoduje to problemu.
Mike Ash ma pełny opis w swoim wpisie na blogu Care and Feeding of Singletons .
Nie wszystkie bloki GCD są uruchamiane asynchronicznie.
źródło