2013-03-17 10 views
12

Ich habe viele Themen und Blogartikel darüber gelesen, wie man ein Singleton in objective-c implementiert, von denen einige vielleicht etwas veraltet sind (Jahr 2010 oder früher), und es sieht so aus, als hätten die Leute unterschiedliche Meinungen zu diesem Thema ... Hat Apple Dokumentation über die Implementierung eines Singletons? Ich konnte es nicht finden. Wenn ja, könnte mir jemand sagen wo?Objective-C Singleton-Muster in iOS 5+

Ich brauche ein Singleton für eine Klasse, die sowohl öffentliche als auch private Variablen hat. Derzeit ist dies die Implementierung, die ich für eine solche Klasse habe:

@interface MySingleton() 
    @property (strong, nonatomic) NSString *state; 
@end 

@implementation MySingleton 

@synthesize state = _state; 
@synthesize count = _count; 

static MySingleton *sharedObject = nil; 

+ (MySingleton *)sharedInstance 
{ 
    static dispatch_once_t _singletonPredicate; 

    dispatch_once(&_singletonPredicate, ^{ 
     sharedObject = [[super allocWithZone:nil] init]; 
    }); 

    return sharedObject; 
} 

+ (id)allocWithZone:(NSZone *)zone 
{ 
    return [self sharedInstance]; 
} 

Sollte dies der empfohlene Weg sein? Und wie sollte ich die Instanzvariablen public und private initialisieren?

Ein anderes Problem, das ich über Singleton klarstellen möchte, ist: Wird dies ein Speicherleck erzeugen? Wird die Verwendung von Singletons tatsächlich in iOS empfohlen?

Dank

+0

In der Tat ... würde das in iOS4 funktionieren? (Als eine Kuriosität.) – Fattie

+0

Und vielleicht hilfreich sein, beachten Sie die außergewöhnlich einfache Darstellung des Codes in der beliebten Antwort hier: http://codereview.stackexchange.com/questions/19829/objective-c-singleton-implementation – Fattie

Antwort

3

In Xcode unter 'Search Dokumentation' eingeben Creating a Singleton Instance. Es gibt viele Ergebnisse (aber der Link oben, am Ende der Seite, hat Beispielcode).

+9

Nicht Verwenden Sie den Code am unteren Rand dieser Seite leicht. Es ist ausschließlich für die Schaffung eines "strengen Singleton", wie es bemerkt. Diese sind äußerst selten in Kakao. Geteilte Singletons sind die Norm und benötigen den Großteil dieses Codes nicht. Dieses Code-Snippet hat unter den neuen Cocoa-Entwicklern für Verwirrung gesorgt. Ich empfehle es zu ignorieren; Es ist unwahrscheinlich, dass Sie auf Fälle treffen, in denen es nützlich ist. –

1

Ja, das ist der empfohlene Weg. Es gibt nur einen kleinen Unterschied, wie ich es benutze: Ich definiere die sharedObject als statische Variable innerhalb der + (MySingleton *)sharedInstance Methode, weil es nicht möglich sein sollte, auf die Variable von irgendwo anders als von der Getter-Methode zuzugreifen.

Und nein, Sie werden kein Speicherleck erstellen. Wenn Ihre App beendet wird, wird der von Ihrer App reservierte reservierte Speicher sowieso freigegeben und es gibt keine andere Situation, in der eine statische freigegebene Instanz freigegeben werden sollte. Im Bereich vor ARC war es sogar üblich, die release Methode zu umgehen, um ein versehentliches Freigeben des Objekts zu verhindern.

+0

Sie meinen 'sharedObject' sollte eine statische Variable sein? –

+0

Oh natürlich. War nur ein Tippfehler. Redigiert es. – miho

12

Das obige ist korrekt, zusammen mit @ miho's Kommentar über das Einschließen des statischen Objekts innerhalb der sharedInstance-Methode. Aber es gibt keinen Grund, +allocWithZone: zu überschreiben. Singletons in ObjC werden im Allgemeinen "geteilt", nicht gezwungen. Sie können andere Instanzen eines "Singletons" erstellen. Wenn es illegal ist, andere Instanzen zu erstellen, sollten Sie init eine NSAssert durchführen, anstatt den Anrufer in +allocWithZone: zu täuschen. Wenn Ihr Singleton veränderbar ist (und die meisten sind), sollten Sie auf keinen Fall +allocWithZone: auf diese Weise überschreiben.

Ein anderes Problem, das ich über Singleton klarstellen möchte, ist: Wird dies ein Speicherleck erzeugen?

Nein. Dieses Objekt wird niemals freigegeben, ist aber immer verfügbar. Das ist kein Leck.

Wird die Verwendung von Singletons tatsächlich in iOS empfohlen?

Ja, und es ist ein sehr häufiges Muster, die alle über das Cocoa-Frameworks verwendet. Das heißt, es gibt verschiedene andere Muster, die in jüngster Zeit unter Entwicklern etwas populär geworden sind. Dependency Injection bekommt ein gewisses Interesse, obwohl ich es in der Praxis nicht oft sehe. Wenn Sie weniger auf Singletons vertrauen, können Sie die Testbarkeit verbessern, und ich habe kürzlich mit dem Versuch experimentiert, einige davon in meinem Code mit einigem Erfolg zu eliminieren. Aber sie haben eine lange, stolze Geschichte in Cocoa, und ich halte sie für kein Problem.

EDIT: Sie haben einen tatsächlichen Fehler in Ihrem Code. Sie sollten [[self alloc] init] anrufen, nicht [[super alloc] init]. Es gibt keinen Grund, jemals anrufen +allocWithZone:, verwenden Sie einfach +alloc. (Die Zeit, wenn ...WithZone: Methoden nützlich waren längst vergangen.)

+0

Ich verstehe das nicht komplett selbst, aber im BNR iOS Buch benutzen sie '[[super allocWithZone: nil] init]' und geben '[self sharedInstance]' in '+ allocWithZone:' zurück. Der Grund dafür ist, dass 'alloc' nur 'allocWithZone' aufruft:' was die eigentliche Zuweisung tut. Die Verwendung von '[super allocWithZone]' verhindert, dass der Code in Kreisen verläuft und seine eigene "allocWithZone" -Methode aufruft. –

+2

ah. Wenn Sie das Überschreiben von 'allocWithZone:' (was Sie fast nie überschreiben sollten) beenden, wird das kein Problem mehr sein. –

+0

Danke! Und sollten dann Variablen durch Überschreiben der 'init'-Methode initialisiert werden, wie in" regulären "Klassen? – AppsDev

0

Ein bisschen Warnung für Singletons mit gcd:

dispatch_once(&_singletonPredicate, ^{ 
     sharedObject = [[super allocWithZone:nil] init]; 
    }); 

wenn die init-Methode aus irgendeinem Grund das Objekt Singleton-Adressen direkt oder indirekt, wird es sei eine Sackgasse. Aus diesem Grunde glaube ich, dass die geeignetere Weise einen Singleton zu schreiben das Verfahren

+ (void) initialize 

ist durch

+1

Warum sollte die init-Methode auf die Singleton-Instanz zugreifen? Ich kann mir keinen Fall vorstellen, in dem das passieren würde. '+ initialize' ist nicht der geeignetere Weg, Singletons zu schreiben, seit GCD veröffentlicht wurde. (Es war ein guter Weg davor.) –

+0

Hallo, Rob :) Ich möchte Ihnen aufrichtig für Ihr wundervolles Buch "iOS-Entwicklung: Grenzen überschreiten" danken, ich habe eine Menge daraus gelernt! Nun, das ist in einer meiner Apps passiert: Die init-Methode hat eine Instanz einer anderen Klasse instanziiert, und diese andere Instanz hat das singleton-Objekt angesprochen, bevor dispatch_once beendet wurde (was Deadlock verursacht). Ja, ich weiß, dass dies aus der Design-Sicht nicht sehr gut ist :) – cpprulez

+0

Genau.Sie haben hier ein Design-Problem, kein Singleton-Muster-Problem. Du machst wahrscheinlich zu viel init. Möglicherweise verwenden Sie auch ein Singleton, das Sie nicht benötigen. Manchmal springen Leute zu schnell zu Singles, wenn es besser wäre, das Objekt einfach zu passieren. –

0

ich immer noch das Singleton-Header Dingen von CocoaWithLove bin mit - etwas veraltet sein kann, aber immer noch wie ein Werk Charme. Es tut im Grunde das gleiche wie beschrieben here Bezug auf Apple-Dokumentation und ich würde davon ausgehen, zumindest Apples Dokumentation (bottom of this page) ist immer noch gültig. Es gibt Leute, die davon ausgehen, dass es unbegrenzt gültig bleibt, denn es ist die offizielle Lösung, die Apple vorgeschlagen hat.

+0

Hi, ja, das ist immer noch gültig, aber es ist nicht effizient, da es bei jedem Zugriff auf das Singleton eine Sperre gibt, auch wenn nur ein Thread versucht, darauf zuzugreifen. dispatch_once löst dieses Problem. – cpprulez