Wie konvertiere (oder erstelle) ich eine Singleton-Klasse, die bei Verwendung der automatischen Referenzzählung (ARC) in Xcode 4.2 kompiliert wird und sich korrekt verhält?
Wie konvertiere (oder erstelle) ich eine Singleton-Klasse, die bei Verwendung der automatischen Referenzzählung (ARC) in Xcode 4.2 kompiliert wird und sich korrekt verhält?
Antworten:
Genau so, wie Sie es bereits hätten tun sollen:
+ (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
Variablen, die innerhalb einer Methode / Funktion deklariert wurden, sind dieselben wie eine static
Variable, die außerhalb einer Methode / Funktion deklariert wurde. Sie sind nur im Rahmen dieser Methode / Funktion gültig. Jeder separater Lauf durch das +sharedInstance
Verfahren (auch auf verschiedene Threads) wird ‚sehen‘ die gleiche sharedInstance
Variable.
Wenn Sie nach Bedarf eine andere Instanz erstellen möchten, gehen Sie wie folgt vor:
+ (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;
}
Andernfalls sollten Sie Folgendes tun:
+ (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 bedeutet, dass Sie auch im ersten Beispiel keine zusätzlichen Instanzen erhalten ...?
[[MyClass alloc] init]
den sharedInstance
Zugriff ausführen und umgehen kann . DongXu, du solltest dir Peter Hoseys Singleton-Artikel ansehen . Wenn Sie überschreiben möchten allocWithZone:
, um zu verhindern, dass weitere Instanzen erstellt werden, sollten Sie auch überschreiben init
, um zu verhindern, dass die gemeinsam genutzte Instanz neu initialisiert wird.
allocWithZone:
Version. Vielen Dank.
Dies ist eine Version für ARC und Nicht-ARC
Wie benutzt man:
MySingletonClass.h
@interface MySingletonClass : NSObject
+(MySingletonClass *)sharedInstance;
@end
MySingletonClass.m
#import "MySingletonClass.h"
#import "SynthesizeSingleton.h"
@implementation MySingletonClass
SYNTHESIZE_SINGLETON_FOR_CLASS(MySingletonClass)
@end
Dies ist mein Muster unter ARC. Erfüllt neue Muster mit GCD und erfüllt auch Apples altes Muster zur Verhinderung der Instanziierung.
@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
dass es sich um eine Instanz der AAA
Oberklasse handelt? Sie müssen rufen Sie +alloc
auf self
, nicht auf super
.
super
bedeutet nicht das Super-Class-Objekt. Sie können kein Super-Class-Objekt abrufen. Dies bedeutet lediglich, dass Nachrichten an die Super-Class-Version der Methode weitergeleitet werden. super
Punkte self
Klasse noch. Wenn Sie ein erstklassiges Objekt erhalten möchten, benötigen Sie Laufzeitreflexionsfunktionen.
-allocWithZone:
Methode ist nur eine einfache Kette zur Zuordnungsfunktion der Laufzeit, um einen übergeordneten Punkt zu bieten. Also letztlich self
Zeiger == aktuelles Klassenobjekt wird allocator weitergegeben werden, und schließlich AAA
wird Instanz zugewiesen werden.
super
in Klassenmethoden funktioniert.
Lesen Sie diese Antwort und lesen Sie dann die andere Antwort.
Sie müssen zuerst wissen, was ein Singleton bedeutet und welche Anforderungen er hat. Wenn Sie ihn nicht verstehen, werden Sie die Lösung überhaupt nicht verstehen!
Um einen Singleton erfolgreich zu erstellen, müssen Sie in der Lage sein, die folgenden 3 Schritte auszuführen:
dispatch_once_t
hilft Ihnen, eine Rennbedingung zu lösen , indem Sie den Block nur einmal versenden lassen.
Static
hilft Ihnen, sich über eine beliebige Anzahl von Aufrufen an seinen Wert zu erinnern. Wie erinnert es sich? Es kann keine neue Instanz mit dem genauen Namen Ihrer sharedInstance erneut erstellt werden. Es funktioniert nur mit der ursprünglich erstellten.
Nicht mit Aufruf alloc
init
(dh wir haben noch alloc
init
Methoden , da wir eine NSObject Unterklasse sind, obwohl wir sie nicht verwenden sollen) auf unserer sharedInstance Klasse, wir dies erreichen durch die Verwendung +(instancetype)sharedInstance
, die nur begrenzt sein wird einmal ausgelöst , unabhängig von mehreren Versuchen von verschiedenen Threads zur gleichen Zeit und erinnern Sie sich an seinen Wert.
Einige der häufigsten System-Singletons, die mit Cocoa selbst geliefert werden, sind:
[UIApplication sharedApplication]
[NSUserDefaults standardUserDefaults]
[NSFileManager defaultManager]
[NSBundle mainBundle]
[NSOperations mainQueue]
[NSNotificationCenter defaultCenter]
Grundsätzlich müsste alles, was einen zentralisierten Effekt haben müsste, einer Art Singleton-Entwurfsmuster folgen.
Alternativ bietet Objective-C die Initialisierungsmethode + (void) für NSObject und alle seine Unterklassen. Es wird immer vor allen Methoden der Klasse aufgerufen.
Ich habe einmal in iOS 6 einen Haltepunkt in einem gesetzt und dispatch_once wurde in den Stapelrahmen angezeigt.
Singleton-Klasse: Niemand kann auf jeden Fall oder auf irgendeine Weise mehr als ein Klassenobjekt erstellen.
+ (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];
}
Es gibt zwei Probleme mit der akzeptierten Antwort, die für Ihren Zweck relevant sein können oder nicht.
Der folgende Code behebt diese beiden Probleme:
+ (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
Hoffe, dass der obige Code Abhilfe schafft.
Wenn Sie schnell Singleton erstellen müssen,
class var sharedInstance: MyClass {
struct Singleton {
static let instance = MyClass()
}
return Singleton.instance
}
oder
struct Singleton {
static let sharedInstance = MyClass()
}
class var sharedInstance: MyClass {
return Singleton.sharedInstance
}
Sie können diesen Weg verwenden
let sharedClass = LibraryAPI.sharedInstance