La tua osservazione è corretta, molti dei modelli "singleton" che vedete in Objective-C non sono single a tutto tranne un modello di "istanza condivisa" in cui è possibile creare altre istanze.
Nei vecchi giorni MRC, Apple aveva un codice di esempio che mostrava come implementare un vero singleton.
Il codice che hai è il modello consigliato per ARC e single thread-safe, non vi resta che metterlo nel metodo init
:
- (instancetype) init
{
static MyClass *initedObject;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
initedObject = [super init];
});
return initedObject;
}
Questo codice farà in modo che ci sia sempre e solo un esempio di MyClass
indipendentemente dal numero di chiamate effettuate da [MyClass new]
o da [[MyClass alloc] init]
.
Questo è tutto ciò che ha bisogno di da fare, ma si può andare oltre. In primo luogo, se si desidera avere un metodo di classe per restituire la Singleton è semplicemente:
+ (instancetype) singletonInstance
{
return [self new];
}
Questo metodo finisce per chiamare init
che restituisce il Singleton, creando se necessario.
If MyClass
attrezzi NSCopying
allora avete anche bisogno di implementare copyWithZone:
- che è il metodo che copy
chiamate. Come hai un Singleton questo è davvero semplice:
- (instancetype) copyWithZone:(NSZone *)zone
{
return self;
}
Infine in Objective-C le operazioni di assegnazione di una nuova istanza dell'oggetto e l'inizializzazione si sono distinti. Lo schema precedente assicura che sia inizializzata e utilizzata una sola istanza di MyClass
, tuttavia per ogni chiamata a new
o alloc
viene allocata un'altra istanza, quindi scartata prontamente da init
e eliminata da ARC. Questo è un po 'dispendioso!
Questo è facilmente indirizzata implementando allocWithZone:
(come copy
sopra questo è il metodo alloc
finisce di chiamata) seguendo lo stesso schema per init
:
+ (instancetype) allocWithZone:(NSZone *)zone
{
static MyClass *allocatedObject;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
allocatedObject = [super allocWithZone:zone];
});
return allocatedObject;
}
La prima volta un'istanza si crea quindi allocWithZone:
sarà allocarlo e quindi init
inizializzarlo, tutte le chiamate successive restituiranno l'oggetto già esistente. Nessuna allocazione non necessaria scartata.
Questo è tutto, un vero singleton, e non più difficile dei finti singoletti che sono così comuni.
HTH
Non dovrebbe usare single in questo modo a tutti. – Sven
@Sven Non è molto utile. Potresti elaborare? Perché non dovrei farlo in questo modo? Sembra essere lo standard. – VeryPoliteNerd
Questo non è altro che lo stato globale mutabile. Non meglio delle variabili globali. Questo porta a un codice difficile da ragionare, difficile da riutilizzare e difficile da testare. Inoltre, ad un certo punto nel tempo probabilmente avrai bisogno di più di una singola istanza. Se hai solo bisogno di una singola istanza, creane solo una. Con la corretta Iniezione delle dipendenze questo è veramente facile da fare. – Sven