Come posso convertire (o creare) una classe singleton che compila e si comporta correttamente quando utilizzo il conteggio dei riferimenti automatici (ARC) in Xcode 4.2?
Come posso convertire (o creare) una classe singleton che compila e si comporta correttamente quando utilizzo il conteggio dei riferimenti automatici (ARC) in Xcode 4.2?
Risposte:
Esattamente allo stesso modo in cui avresti dovuto (già) farlo:
+ (instancetype)sharedInstance
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MyClass alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
static
variabili @David dichiarate all'interno di un metodo / funzione sono le stesse di una static
variabile dichiarata al di fuori di un metodo / funzione, sono valide solo nell'ambito di tale metodo / funzione. Ogni esecuzione separata attraverso il +sharedInstance
metodo (anche su thread diversi) "vedrà" la stessa sharedInstance
variabile.
se si desidera creare un'altra istanza secondo necessità.
+ (MyClass *)sharedInstance
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MyClass alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
altrimenti, dovresti fare questo:
+ (id)allocWithZone:(NSZone *)zone
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
dispatch_once()
bit indica che non otterrai ulteriori istanze, anche nel primo esempio ...?
[[MyClass alloc] init]
e bypassare l' sharedInstance
accesso. DongXu, dovresti guardare l'articolo Singleton di Peter Hosey . Se si intende eseguire l'override allocWithZone:
per impedire la creazione di più istanze, è necessario eseguire init
l' override per impedire la reinizializzazione dell'istanza condivisa.
allocWithZone:
versione. Grazie.
Questa è una versione per ARC e non ARC
Come usare:
MySingletonClass.h
@interface MySingletonClass : NSObject
+(MySingletonClass *)sharedInstance;
@end
MySingletonClass.m
#import "MySingletonClass.h"
#import "SynthesizeSingleton.h"
@implementation MySingletonClass
SYNTHESIZE_SINGLETON_FOR_CLASS(MySingletonClass)
@end
Questo è il mio modello sotto ARC. Soddisfa il nuovo modello utilizzando GCD e soddisfa anche il vecchio modello di prevenzione delle istanze di Apple.
@implementation AAA
+ (id)alloc
{
return [self allocWithZone:nil];
}
+ (id)allocWithZone:(NSZone *)zone
{
[self doesNotRecognizeSelector:_cmd];
abort();
}
+ (instancetype)theController
{
static AAA* c1 = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
c1 = [[super allocWithZone:nil] init];
// For confirm...
NSLog(@"%@", NSStringFromClass([c1 class])); // Prints AAA
NSLog(@"%@", @([c1 class] == self)); // Prints 1
Class real_superclass_obj = class_getSuperclass(self);
NSLog(@"%@", @(real_superclass_obj == self)); // Prints 0
});
return c1;
}
@end
c1
sarà un'istanza della AAA
superclasse? È necessario chiamare +alloc
il self
, non su super
.
super
non significa l'oggetto superclasse . Non è possibile ottenere oggetti di classe superiore Significa semplicemente instradare i messaggi alla versione di classe classe del metodo. super
indica ancora la self
classe. Se si desidera ottenere un oggetto di classe superiore, è necessario ottenere le funzioni di riflessione del runtime.
-allocWithZone:
metodo è solo una semplice catena per la funzione di allocazione del runtime per offrire un punto di esclusione. Quindi, alla fine, self
pointer == l'oggetto classe corrente verrà passato all'allocatore e infine AAA
verrà allocata l'istanza.
super
funzionano i metodi di classe.
Leggi questa risposta e poi vai a leggere l'altra risposta.
Devi prima sapere cosa significa Singleton e quali sono i suoi requisiti, se non lo capisci, allora non capirai affatto la soluzione!
Per creare correttamente un Singleton devi essere in grado di eseguire le seguenti 3:
dispatch_once_t
ti aiuta a risolvere una condizione di gara permettendo che il suo blocco venga spedito una sola volta.
Static
ti aiuta a "ricordare" il suo valore su qualsiasi numero di invocazioni. Come si ricorda? Non consente di creare nuovamente alcuna nuova istanza con lo stesso nome di sharedInstance, ma funziona solo con quella creata originariamente.
Non usando la chiamata alloc
init
(ovvero disponiamo ancora di alloc
init
metodi poiché siamo una sottoclasse NSObject, sebbene NON dovremmo usarli) sulla nostra classe sharedInstance, lo otteniamo utilizzando +(instancetype)sharedInstance
, che è destinato a essere avviato solo una volta , indipendentemente da più tentativi da thread diversi allo stesso tempo e ricordare il suo valore.
Alcuni dei Singleton di sistema più comuni forniti con il cacao stesso sono:
[UIApplication sharedApplication]
[NSUserDefaults standardUserDefaults]
[NSFileManager defaultManager]
[NSBundle mainBundle]
[NSOperations mainQueue]
[NSNotificationCenter defaultCenter]
Fondamentalmente tutto ciò che dovrebbe avere un effetto centralizzato dovrebbe seguire una sorta di modello di progettazione Singleton.
In alternativa, Objective-C fornisce il metodo + (void) di inizializzazione per NSObject e tutte le sue sottoclassi. Viene sempre chiamato prima di qualsiasi metodo della classe.
Ho impostato un breakpoint in uno una volta in iOS 6 e dispatch_once è apparso nei frame dello stack.
Classe Singleton: nessuno può creare più di un oggetto di classe in nessun caso o in alcun modo.
+ (instancetype)sharedInstance
{
static ClassName *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[ClassName alloc] init];
// Perform other initialisation...
});
return sharedInstance;
}
// You need need to override init method as well, because developer can call [[MyClass alloc]init] method also. that time also we have to return sharedInstance only.
-(MyClass)init
{
return [ClassName sharedInstance];
}
Esistono due problemi con la risposta accettata, che possono essere o non essere pertinenti ai tuoi scopi.
Il codice seguente si occupa di entrambi questi problemi:
+ (instancetype)sharedInstance {
static id mutex = nil;
static NSMutableDictionary *instances = nil;
//Initialize the mutex and instances dictionary in a thread safe manner
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
mutex = [NSObject new];
instances = [NSMutableDictionary new];
});
id instance = nil;
//Now synchronize on the mutex
//Note: do not synchronize on self, since self may differ depending on which class this method is called on
@synchronized(mutex) {
id <NSCopying> key = (id <NSCopying>)self;
instance = instances[key];
if (instance == nil) {
//Break allocation and initialization into two statements to prevent a stack overflow, if init somehow calls the sharedInstance method
id allocatedInstance = [self alloc];
//Store the instance into the dictionary, one per concrete class (class acts as key for the dictionary)
//Do this right after allocation to avoid the stackoverflow problem
if (allocatedInstance != nil) {
instances[key] = allocatedInstance;
}
instance = [allocatedInstance init];
//Following code may be overly cautious
if (instance != allocatedInstance) {
//Somehow the init method did not return the same instance as the alloc method
if (instance == nil) {
//If init returns nil: immediately remove the instance again
[instances removeObjectForKey:key];
} else {
//Else: put the instance in the dictionary instead of the allocatedInstance
instances[key] = instance;
}
}
}
}
return instance;
}
#import <Foundation/Foundation.h>
@interface SingleTon : NSObject
@property (nonatomic,strong) NSString *name;
+(SingleTon *) theSingleTon;
@end
#import "SingleTon.h"
@implementation SingleTon
+(SingleTon *) theSingleTon{
static SingleTon *theSingleTon = nil;
if (!theSingleTon) {
theSingleTon = [[super allocWithZone:nil] init
];
}
return theSingleTon;
}
+(id)allocWithZone:(struct _NSZone *)zone{
return [self theSingleTon];
}
-(id)init{
self = [super init];
if (self) {
// Set Variables
_name = @"Kiran";
}
return self;
}
@end
Spero che il codice sopra lo aiuti.
se devi creare singleton in rapido,
class var sharedInstance: MyClass {
struct Singleton {
static let instance = MyClass()
}
return Singleton.instance
}
o
struct Singleton {
static let sharedInstance = MyClass()
}
class var sharedInstance: MyClass {
return Singleton.sharedInstance
}
puoi usare in questo modo
let sharedClass = LibraryAPI.sharedInstance