Jak powinien wyglądać mój Objective-C singleton? [zamknięte]
Moja metoda singleton accessor to zazwyczaj jakiś wariant:
static MyClass *gInstance = NULL;
+ (MyClass *)instance
{
@synchronized(self)
{
if (gInstance == NULL)
gInstance = [[self alloc] init];
}
return(gInstance);
}
Co mógłbym zrobić, aby to poprawić?
26 answers
Inną opcją jest użycie metody +(void)initialize
. Z dokumentacji:
Runtime wysyła
initialize
do każdej klasy w programie dokładnie jeden raz, tuż przed klasą lub jakąkolwiek klasą, która z niej dziedziczy, zostanie wysłana pierwsza wiadomość z programu. (Tak więc metoda nigdy nie może być wywołana, jeśli klasa nie jest używana.) Runtime wysyła wiadomośćinitialize
do klas w sposób bezpieczny dla wątku. Superklasy otrzymują tę wiadomość przed ich podklasami.
Żebyś mógł zrób coś podobnego do tego:
static MySingleton *sharedSingleton;
+ (void)initialize
{
static BOOL initialized = NO;
if(!initialized)
{
initialized = YES;
sharedSingleton = [[MySingleton alloc] init];
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-27 02:14:23
@interface MySingleton : NSObject
{
}
+ (MySingleton *)sharedSingleton;
@end
@implementation MySingleton
+ (MySingleton *)sharedSingleton
{
static MySingleton *sharedSingleton;
@synchronized(self)
{
if (!sharedSingleton)
sharedSingleton = [[MySingleton alloc] init];
return sharedSingleton;
}
}
@end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-28 04:23:16
Według mojej innej Odpowiedzi poniżej, myślę, że powinieneś zrobić:
+ (id)sharedFoo
{
static dispatch_once_t once;
static MyFoo *sharedFoo;
dispatch_once(&once, ^ { sharedFoo = [[self alloc] init]; });
return sharedFoo;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-19 23:24:34
Ponieważ Kendall opublikował threadsafe singleton, który próbuje uniknąć kosztów blokowania, pomyślałem, że wrzucę też jeden:
#import <libkern/OSAtomic.h>
static void * volatile sharedInstance = nil;
+ (className *) sharedInstance {
while (!sharedInstance) {
className *temp = [[self alloc] init];
if(!OSAtomicCompareAndSwapPtrBarrier(0x0, temp, &sharedInstance)) {
[temp release];
}
}
return sharedInstance;
}
Ok, pozwól mi wyjaśnić, jak to działa:
-
Szybki przypadek: w normalnym wykonaniu
sharedInstance
zostało już ustawione, więc pętlawhile
nigdy nie jest wykonywana, a funkcja powraca po prostu po sprawdzeniu istnienia zmiennej; Powolna wielkość liter: Jeśli
sharedInstance
nie istnieje, wtedy instancja jest przydzielana i kopiowana do niej using a Compare And Swap ("CAS');Jeśli dwa wątki jednocześnie próbują wywołać
sharedInstance
isharedInstance
nie istnieje w tym samym czasie, a następnie obie zainicjalizują nowe instancje Singletona i spróbują go ustawić na swoim miejscu. Niezależnie od tego, który z nich wygra, CAS zwróci natychmiast, a który przegra, zwolni instancję, którą właśnie przydzielił i zwróci (teraz ustawione)sharedInstance
. PojedynczyOSAtomicCompareAndSwapPtrBarrier
działa zarówno jako bariera zapisu dla wątku ustawień, jak i bariera odczytu z wątku testowego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:29:47
static MyClass *sharedInst = nil; + (id)sharedInstance { @synchronize( self ) { if ( sharedInst == nil ) { /* sharedInst set up in init */ [[self alloc] init]; } } return sharedInst; } - (id)init { if ( sharedInst != nil ) { [NSException raise:NSInternalInconsistencyException format:@"[%@ %@] cannot be called; use +[%@ %@] instead"], NSStringFromClass([self class]), NSStringFromSelector(_cmd), NSStringFromClass([self class]), NSStringFromSelector(@selector(sharedInstance)"]; } else if ( self = [super init] ) { sharedInst = self; /* Whatever class specific here */ } return sharedInst; } /* These probably do nothing in a GC app. Keeps singleton as an actual singleton in a non CG app */ - (NSUInteger)retainCount { return NSUIntegerMax; } - (oneway void)release { } - (id)retain { return sharedInst; } - (id)autorelease { return sharedInst; }
Edit: Ta implementacja jest przestarzała z ARC. Proszę spojrzeć na jak zaimplementować Objective-C singleton, który jest kompatybilny z ARC? do poprawnej realizacji.
Wszystkie implementacje initialize, które czytałem w innych odpowiedziach, mają wspólny błąd.
+ (void) initialize {
_instance = [[MySingletonClass alloc] init] // <----- Wrong!
}
+ (void) initialize {
if (self == [MySingletonClass class]){ // <----- Correct!
_instance = [[MySingletonClass alloc] init]
}
}
Dokumentacja Apple zaleca sprawdzenie typu klasy w bloku inicjalizacji. Ponieważ podklasy domyślnie wywołują initialize. Istnieje nieoczywisty przypadek, w którym podklasy mogą być tworzone pośrednio poprzez KVO. Jeśli dodasz następujący wiersz w innej klasie:
[[MySingletonClass getInstance] addObserver:self forKeyPath:@"foo" options:0 context:nil]
Objective-C domyślnie utworzy podklasę MySingletonClass, co spowoduje drugie uruchomienie +initialize
.
Możesz pomyśleć, że powinieneś domyślnie sprawdzić duplikat inicjalizacji w bloku init jako taki:
- (id) init { <----- Wrong!
if (_instance != nil) {
// Some hack
}
else {
// Do stuff
}
return self;
}
Ale strzelisz sobie w stopę, albo co gorsza dasz innemu deweloperowi możliwość strzelania sobie w stopa.
- (id) init { <----- Correct!
NSAssert(_instance == nil, @"Duplication initialization of singleton");
self = [super init];
if (self){
// Do stuff
}
return self;
}
TL; DR, oto moja implementacja
@implementation MySingletonClass
static MySingletonClass * _instance;
+ (void) initialize {
if (self == [MySingletonClass class]){
_instance = [[MySingletonClass alloc] init];
}
}
- (id) init {
ZAssert (_instance == nil, @"Duplication initialization of singleton");
self = [super init];
if (self) {
// Initialization
}
return self;
}
+ (id) getInstance {
return _instance;
}
@end
(Zastąp ZAssert naszym własnym makrem twierdzenia; lub po prostu NSAssert.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:35
Dokładne wyjaśnienie kodu makra Singletona znajduje się na blogu Cocoa With Love
Http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-12 22:45:37
Mam ciekawą odmianę sharedInstance, która jest bezpieczna dla wątków, ale nie blokuje się po inicjalizacji. Nie jestem jeszcze na tyle pewien, aby zmodyfikować górną odpowiedź zgodnie z żądaniem, ale przedstawiam ją do dalszej dyskusji: {]}
// Volatile to make sure we are not foiled by CPU caches
static volatile ALBackendRequestManager *sharedInstance;
// There's no need to call this directly, as method swizzling in sharedInstance
// means this will get called after the singleton is initialized.
+ (MySingleton *)simpleSharedInstance
{
return (MySingleton *)sharedInstance;
}
+ (MySingleton*)sharedInstance
{
@synchronized(self)
{
if (sharedInstance == nil)
{
sharedInstance = [[MySingleton alloc] init];
// Replace expensive thread-safe method
// with the simpler one that just returns the allocated instance.
SEL origSel = @selector(sharedInstance);
SEL newSel = @selector(simpleSharedInstance);
Method origMethod = class_getClassMethod(self, origSel);
Method newMethod = class_getClassMethod(self, newSel);
method_exchangeImplementations(origMethod, newMethod);
}
}
return (MySingleton *)sharedInstance;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-19 08:00:33
Krótka odpowiedź: Bajeczna.
Długa odpowiedź: coś w tym stylu....static SomeSingleton *instance = NULL;
@implementation SomeSingleton
+ (id) instance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (instance == NULL){
instance = [[super allocWithZone:NULL] init];
}
});
return instance;
}
+ (id) allocWithZone:(NSZone *)paramZone {
return [[self instance] retain];
}
- (id) copyWithZone:(NSZone *)paramZone {
return self;
}
- (id) autorelease {
return self;
}
- (NSUInteger) retainCount {
return NSUIntegerMax;
}
- (id) retain {
return self;
}
@end
Pamiętaj, aby przeczytać dispatch/raz.header h , aby zrozumieć, co się dzieje. W tym przypadku komentarze nagłówka są bardziej odpowiednie niż dokumenty lub strona podręcznika.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-08 03:12:32
Przeniosłem singleton do klasy, więc inne klasy mogą dziedziczyć właściwości Singletona.
Singleton.h:static id sharedInstance = nil;
#define DEFINE_SHARED_INSTANCE + (id) sharedInstance { return [self sharedInstance:&sharedInstance]; } \
+ (id) allocWithZone:(NSZone *)zone { return [self allocWithZone:zone forInstance:&sharedInstance]; }
@interface Singleton : NSObject {
}
+ (id) sharedInstance;
+ (id) sharedInstance:(id*)inst;
+ (id) allocWithZone:(NSZone *)zone forInstance:(id*)inst;
@end
Singleton.m:
#import "Singleton.h"
@implementation Singleton
+ (id) sharedInstance {
return [self sharedInstance:&sharedInstance];
}
+ (id) sharedInstance:(id*)inst {
@synchronized(self)
{
if (*inst == nil)
*inst = [[self alloc] init];
}
return *inst;
}
+ (id) allocWithZone:(NSZone *)zone forInstance:(id*)inst {
@synchronized(self) {
if (*inst == nil) {
*inst = [super allocWithZone:zone];
return *inst; // assignment and return on first allocation
}
}
return nil; // on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; // denotes an object that cannot be released
}
- (void)release {
//do nothing
}
- (id)autorelease {
return self;
}
@end
A oto przykład jakiejś klasy, którą chcesz zostać singletonem.
#import "Singleton.h"
@interface SomeClass : Singleton {
}
@end
@implementation SomeClass
DEFINE_SHARED_INSTANCE;
@end
Jedynym ograniczeniem klasy Singleton jest to, że jest to podklasa NSObject. Ale większość czasu używam singletons w moim kodzie są w rzeczywistości NSObject podklasy, więc ta klasa naprawdę ułatwiają mi życie i uczynić kod czystszym.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-30 10:00:44
To działa również w środowisku nie-śmieci zbierane.
@interface MySingleton : NSObject {
}
+(MySingleton *)sharedManager;
@end
@implementation MySingleton
static MySingleton *sharedMySingleton = nil;
+(MySingleton*)sharedManager {
@synchronized(self) {
if (sharedMySingleton == nil) {
[[self alloc] init]; // assignment not done here
}
}
return sharedMySingleton;
}
+(id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if (sharedMySingleton == nil) {
sharedMySingleton = [super allocWithZone:zone];
return sharedMySingleton; // assignment and return on first allocation
}
}
return nil; //on subsequent allocation attempts return nil
}
-(void)dealloc {
[super dealloc];
}
-(id)copyWithZone:(NSZone *)zone {
return self;
}
-(id)retain {
return self;
}
-(unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be release
}
-(void)release {
//do nothing
}
-(id)autorelease {
return self;
}
-(id)init {
self = [super init];
sharedMySingleton = self;
//initialize here
return self;
}
@end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-10 14:48:40
Czy to nie powinno być threadsafe i uniknąć kosztownego blokowania po pierwszym połączeniu?
+ (MySingleton*)sharedInstance
{
if (sharedInstance == nil) {
@synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [[MySingleton alloc] init];
}
}
}
return (MySingleton *)sharedInstance;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-17 11:13:55
Oto makro , które złożyłem:
Http://github.com/cjhanson/Objective-C-Optimized-Singleton
[[0]} opiera się na pracy Matta Gallaghera Jednak zmiana implementacji na metodę opisaną tutaj przez Dave ' a Maclachlana z Google .Zapraszam do komentowania / komentowania.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-13 15:25:03
A może
static MyClass *gInstance = NULL;
+ (MyClass *)instance
{
if (gInstance == NULL) {
@synchronized(self)
{
if (gInstance == NULL)
gInstance = [[self alloc] init];
}
}
return(gInstance);
}
Więc unikasz kosztów synchronizacji po inicjalizacji?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-29 18:32:32
Szczegółowe omówienie wzorca Singletona w Objective-C znajduje się tutaj:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-28 02:15:12
KLSingleton to:
- Podkategoria (do n-tego stopnia)
- Arc compatible
- bezpieczne z
alloc
iinit
- Loaded leniwie
- thread-safe
- Lock-free (używa +initialize, nie @synchronize)
- makro-free
- swizzle-free
- proste
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-11 20:54:30
Nie chcesz synchronizować się na sobie... Ponieważ obiekt jaźni jeszcze nie istnieje! Kończy się zablokowaniem tymczasowej wartości id. Chcesz się upewnić, że nikt inny nie może uruchamiać metod klasy( sharedInstance, alloc, allocWithZone:, itd.), więc musisz zsynchronizować obiekt klasy:
@implementation MYSingleton
static MYSingleton * sharedInstance = nil;
+( id )sharedInstance {
@synchronized( [ MYSingleton class ] ) {
if( sharedInstance == nil )
sharedInstance = [ [ MYSingleton alloc ] init ];
}
return sharedInstance;
}
+( id )allocWithZone:( NSZone * )zone {
@synchronized( [ MYSingleton class ] ) {
if( sharedInstance == nil )
sharedInstance = [ super allocWithZone:zone ];
}
return sharedInstance;
}
-( id )init {
@synchronized( [ MYSingleton class ] ) {
self = [ super init ];
if( self != nil ) {
// Insert initialization code here
}
return self;
}
}
@end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-13 22:07:14
Chciałem to tu zostawić, żebym go nie zgubił. Zaletą tego jest to, że można go używać w Interfejsiebuilder, co jest ogromną zaletą. to pochodzi z innego pytania, które zadałem :
static Server *instance;
+ (Server *)instance { return instance; }
+ (id)hiddenAlloc
{
return [super alloc];
}
+ (id)alloc
{
return [[self instance] retain];
}
+ (void)initialize
{
static BOOL initialized = NO;
if(!initialized)
{
initialized = YES;
instance = [[Server hiddenAlloc] init];
}
}
- (id) init
{
if (instance)
return self;
self = [super init];
if (self != nil) {
// whatever
}
return self;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:10
static mySingleton *obj=nil;
@implementation mySingleton
-(id) init {
if(obj != nil){
[self release];
return obj;
} else if(self = [super init]) {
obj = self;
}
return obj;
}
+(mySingleton*) getSharedInstance {
@synchronized(self){
if(obj == nil) {
obj = [[mySingleton alloc] init];
}
}
return obj;
}
- (id)retain {
return self;
}
- (id)copy {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; // denotes an object that cannot be released
}
- (void)release {
if(obj != self){
[super release];
}
//do nothing
}
- (id)autorelease {
return self;
}
-(void) dealloc {
[super dealloc];
}
@end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-03 18:40:09
Wiem, że jest wiele komentarzy na temat tego "pytania", ale nie widzę wielu osób sugerujących użycie makra do zdefiniowania Singletona. To taki powszechny wzór, a Makro znacznie upraszcza singleton.
Oto makra, które napisałem na podstawie kilku implementacji obiektów, które widziałem.
Singeton.h
/**
@abstract Helps define the interface of a singleton.
@param TYPE The type of this singleton.
@param NAME The name of the singleton accessor. Must match the name used in the implementation.
@discussion
Typcially the NAME is something like 'sharedThing' where 'Thing' is the prefix-removed type name of the class.
*/
#define SingletonInterface(TYPE, NAME) \
+ (TYPE *)NAME;
/**
@abstract Helps define the implementation of a singleton.
@param TYPE The type of this singleton.
@param NAME The name of the singleton accessor. Must match the name used in the interface.
@discussion
Typcially the NAME is something like 'sharedThing' where 'Thing' is the prefix-removed type name of the class.
*/
#define SingletonImplementation(TYPE, NAME) \
static TYPE *__ ## NAME; \
\
\
+ (void)initialize \
{ \
static BOOL initialized = NO; \
if(!initialized) \
{ \
initialized = YES; \
__ ## NAME = [[TYPE alloc] init]; \
} \
} \
\
\
+ (TYPE *)NAME \
{ \
return __ ## NAME; \
}
Przykład użycia:
MyManager.h
@interface MyManager
SingletonInterface(MyManager, sharedManager);
// ...
@end
MyManager.m
@implementation MyManager
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
SingletonImplementation(MyManager, sharedManager);
// ...
@end
Dlaczego makro interfejsu, gdy jest prawie puste? Spójność kodu między nagłówkiem a pliki kodu; konserwacja w przypadku, gdy chcesz dodać więcej automatycznych metod lub zmienić je.
Używam metody initialize, aby utworzyć singleton, jak jest używany w najpopularniejszej odpowiedzi tutaj (w momencie pisania).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-22 20:00:41
Z metodami Objective C class, możemy po prostu uniknąć używania wzorca Singletona w zwykły sposób, z:
[[Librarian sharedInstance] openLibrary]
Do:
[Librarian openLibrary]
Zawijając klasę wewnątrz innej klasy, która ma tylko metody klasy , w ten sposób nie ma szans na przypadkowe utworzenie zduplikowanych instancji, ponieważ nie tworzymy żadnej instancji!
Napisałem bardziej szczegółowy blog tutaj :)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-10 22:35:08
Aby rozszerzyć przykład z @ robbie-hanson ...
static MySingleton* sharedSingleton = nil;
+ (void)initialize {
static BOOL initialized = NO;
if (!initialized) {
initialized = YES;
sharedSingleton = [[self alloc] init];
}
}
- (id)init {
self = [super init];
if (self) {
// Member initialization here.
}
return self;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-22 16:52:31
Mój sposób jest prosty:
static id instanceOfXXX = nil;
+ (id) sharedXXX
{
static volatile BOOL initialized = NO;
if (!initialized)
{
@synchronized([XXX class])
{
if (!initialized)
{
instanceOfXXX = [[XXX alloc] init];
initialized = YES;
}
}
}
return instanceOfXXX;
}
Jeśli singleton jest już zainicjowany, blok blokady nie zostanie wprowadzony. Drugi sprawdź, czy (!initialized) ma na celu upewnienie się, że nie została jeszcze zainicjowana, gdy bieżący wątek uzyska blokadę.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-24 06:45:56
Nie przeczytałem wszystkich rozwiązań, więc wybacz, że ten kod jest zbędny.
Jest to moim zdaniem najbardziej bezpieczna implementacja wątku.
+(SingletonObject *) sharedManager
{
static SingletonObject * sharedResourcesObj = nil;
@synchronized(self)
{
if (!sharedResourcesObj)
{
sharedResourcesObj = [[SingletonObject alloc] init];
}
}
return sharedResourcesObj;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-06 19:56:53
Zwykle używam kodu mniej więcej podobnego do tego w odpowiedzi Bena Hoffsteina (którą też wyciągnąłem z Wikipedii). Używam go z powodów podanych przez Chrisa Hansona w jego komentarzu.
Jednak czasami mam potrzebę umieszczenia Singletona w stalówce i w takim przypadku używam następującego:
@implementation Singleton
static Singleton *singleton = nil;
- (id)init {
static BOOL initialized = NO;
if (!initialized) {
self = [super init];
singleton = self;
initialized = YES;
}
return self;
}
+ (id)allocWithZone:(NSZone*)zone {
@synchronized (self) {
if (!singleton)
singleton = [super allocWithZone:zone];
}
return singleton;
}
+ (Singleton*)sharedSingleton {
if (!singleton)
[[Singleton alloc] init];
return singleton;
}
@end
Zostawiam implementację -retain
(itd.) do czytelnika, chociaż powyższy kod jest wszystkim, czego potrzebujesz w środowisku śmieci.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-24 04:53:41
Przyjęta odpowiedź, mimo że jest kompilowana, jest niepoprawna.
+ (MySingleton*)sharedInstance
{
@synchronized(self) <-------- self does not exist at class scope
{
if (sharedInstance == nil)
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
Na dokumentację Apple:
... Można zastosować podobne podejście do synchronizacji metod klas powiązanych klas, używając obiektu klasy zamiast self.
Nawet jeśli używanie self działa, nie powinno i wygląda to jak błąd kopiowania i wklejania. Poprawną implementacją metody class factory byłoby:
+ (MySingleton*)getInstance
{
@synchronized([MySingleton class])
{
if (sharedInstance == nil)
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-24 04:56:54