Jeśli możesz kierować system iOS 4.0 lub nowszy
Czy używając GCD to najlepszy sposób na utworzenie singletonu w Objective-C (wątek bezpieczny)?
+ (instancetype)sharedInstance
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
instancetype
. Uzupełnianie kodu jest znacznie lepsze, gdy używasz go zamiastid
.Odpowiedzi:
Jest to całkowicie akceptowalny i bezpieczny w wątkach sposób tworzenia instancji swojej klasy. Technicznie może to nie być „singleton” (ponieważ może istnieć tylko jeden z tych obiektów), ale dopóki używasz tylko
[Foo sharedFoo]
metody dostępu do obiektu, jest to wystarczająco dobre.źródło
typ instancet
instancetype
jest tylko jednym z wielu rozszerzeń językowychObjective-C
, z każdym nowym dodatkiem dodawanym.Wiedz to, kochaj to.
I weź to jako przykład tego, w jaki sposób zwracanie uwagi na szczegóły niskiego poziomu może dać ci wgląd w nowe potężne sposoby transformacji Celu C.
Zobacz tutaj: typ instancet
źródło
MySingleton.h
MySingleton.m
źródło
init
?MySingleton
, na przykład,MySingleton.m
dzwonię[super alloc]
Można uniknąć przydzielenia klasy poprzez zastąpienie metody przydzielania.
źródło
Dave ma rację, w porządku. Możesz zapoznać się z dokumentami Apple dotyczącymi tworzenia singletonu, aby uzyskać wskazówki dotyczące implementacji niektórych innych metod, aby upewnić się, że tylko jedna może zostać utworzona, jeśli klasy zdecydują się NIE używać metody sharedFoo.
źródło
Jeśli chcesz się upewnić, że [[MyClass przydzielone] init] zwraca ten sam obiekt co sharedInstance (moim zdaniem nie jest to konieczne, ale niektórzy ludzie tego chcą), można to zrobić bardzo łatwo i bezpiecznie za pomocą drugiego dispatch_once:
Pozwala to dowolnej kombinacji [[MyClass przydziału] init] i [MyClass sharedInstance] zwrócić ten sam obiekt; [MyClass sharedInstance] byłby tylko trochę bardziej wydajny. Jak to działa: [MyClass sharedInstance] wywoła [inicjację [MyClass]] raz] jeden raz. Inny kod może go również wywołać dowolną liczbę razy. Pierwszy dzwoniący do init wykona „normalną” inicjalizację i zapisze obiekt singletonu z dala od metody init. Wszelkie późniejsze wywołania init będą całkowicie ignorować to, co alokacja zwróciło i zwróci tę samą sharedInstance; wynik alokacji zostanie anulowany.
Metoda + sharedInstance będzie działać jak zawsze. Jeśli nie jest to pierwszy dzwoniący, który wywołuje [[MyClass przydzielone] init], to wynik init nie jest wynikiem połączenia przydzielającego, ale jest w porządku.
źródło
Pytasz, czy to „najlepszy sposób na stworzenie singletonu”.
Kilka myśli:
Po pierwsze, tak, jest to rozwiązanie bezpieczne dla wątków. Ten
dispatch_once
wzór jest nowoczesnym, bezpiecznym dla wątków sposobem generowania singletonów w Objective-C. Nie martw się tam.Zapytałeś jednak, czy jest to „najlepszy” sposób na zrobienie tego. Należy jednak uznać, że
instancetype
i[[self alloc] init]
jest potencjalnie mylące, gdy jest używane w połączeniu z singletonami.Zaletą tego
instancetype
jest to, że jest to jednoznaczny sposób zadeklarowania, że klasę można podklasować bez uciekania się do pewnego rodzajuid
, jak to robiliśmy w przeszłości.Ale
static
w tej metodzie przedstawia się wyzwania związane z podklasowaniem. Co jeśliImageCache
iBlobCache
singletons były zarówno podklasy zeCache
nadrzędnej bez wdrożenie własnejsharedCache
metody?Aby to zadziałało, musisz upewnić się, że podklasy implementują własną
sharedInstance
(lub jakkolwiek to nazwiesz dla konkretnej klasy) metodę.Podsumowując, twój oryginalny
sharedInstance
wygląd będzie obsługiwał podklasy, ale nie będzie. Jeśli zamierzasz wspierać podklasowanie, dołącz przynajmniej dokumentację, która ostrzega przyszłych programistów, że muszą zastąpić tę metodę.Aby uzyskać najlepszą interoperacyjność z Swift, prawdopodobnie chcesz zdefiniować to jako właściwość, a nie metodę klasy, np .:
Następnie możesz napisać getter dla tej właściwości (implementacja
dispatch_once
użyłaby zaproponowanego wzorca):Zaletą tego jest to, że jeśli użytkownik Swift z niego skorzysta, zrobiłby coś takiego:
Uwaga, nie ma
()
, ponieważ zaimplementowaliśmy go jako właściwość. Począwszy od wersji Swift 3, w ten sposób zazwyczaj uzyskuje się dostęp do singletonów. Tak więc zdefiniowanie go jako właściwości ułatwia tę interoperacyjność.Nawiasem mówiąc, jeśli spojrzysz na to, jak Apple definiuje ich singletony, jest to wzorzec, który przyjęli, np. Ich
NSURLSession
singleton jest zdefiniowany w następujący sposób:Inną, bardzo niewielką kwestią dotyczącą szybkiej interoperacyjności była nazwa singletonu. Najlepiej, jeśli zamiast tego możesz podać nazwę typu
sharedInstance
. Na przykład, jeśli klasa byłaFoo
, możesz zdefiniować właściwość singleton jakosharedFoo
. Lub jeśli klasa byłaDatabaseManager
, możesz zadzwonić do nieruchomościsharedManager
. Następnie użytkownicy Swift mogliby:Oczywiście, jeśli naprawdę chcesz używać
sharedInstance
, zawsze możesz zadeklarować nazwę Swift, jeśli chcesz:Oczywiście, pisząc kod Celu-C, nie powinniśmy pozwolić, aby interoperacyjność Swift przeważała nad innymi względami projektowymi, ale mimo to, jeśli możemy napisać kod, który z wdziękiem obsługuje oba języki, jest to preferowane.
Zgadzam się z innymi, którzy podkreślają, że jeśli chcesz, aby był to prawdziwy singleton, w którym programiści nie mogą / nie powinni (przypadkowo) tworzyć własnych instancji,
unavailable
kwalifikator jest włączonyinit
inew
jest ostrożny.źródło
Aby utworzyć singleton bezpieczny dla wątków, możesz wykonać następujące czynności:
i ten blog bardzo dobrze tłumaczy singletony w objc / cocoa
źródło
źródło
źródło