Frage

Ich bin mit dem Singletonmuster an mehreren Stellen in einer Anwendung, und ich bin Speicherverlust Fehler von clang bekommen, wenn Sie den Code zu analysieren.

static MyClass *_sharedMyClass;
+ (MyClass *)sharedMyClass {
  @synchronized(self) {
    if (_sharedMyClass == nil)
      [[self alloc] init];
  }
  return _sharedMyClass;
}

// clang error: Object allocated on line 5 is no longer referenced after this point and has a retain count of +1 (object leaked)

Ich verwende diese Einstellungen für scan-build:

scan-build -v -v -v -V -k xcodebuild

Ich bin ziemlich sicher, dass der Code in der Singleton ganz gut ist - immerhin, es ist der gleiche Code hier auf Stack-Überlauf als auch in Apples Dokumentation verwiesen wird - aber ich mag die Speicherverlust Warnung so aussortiert erhalten mein Scan-build kehrt Erfolg.

War es hilfreich?

Lösung

ich sein kann, außerordentlich dicht ist, aber sicher Ihre Linie 5

[[self alloc] init];

ordnet ein Objekt des enthaltenden Klasse-Typs, und wirft ihn sofort weg? Haben Sie nicht wollen,

_sharedMyClass = [[self alloc] init];

Andere Tipps

Apple hat seit aktualisiert empfohlen Singleton Code den statischen Analysator weitergeben müssen:

+ (MyGizmoClass*)sharedManager
{
    if (sharedGizmoManager == nil) {
        sharedGizmoManager = [[super allocWithZone:NULL] init];
    }
    return sharedGizmoManager;
}

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

Jetzt +sharedManager ruft Super die -allocWithZone: und ordnet die Rückkehr von -init und die Singletons -allocWithZone: gibt nur eine beibehaltene sharedInstance.

Edit:

Warum behalten die in + allocWithZone:

+ allocWithZone: außer Kraft gesetzt wird, weil jemand MyGizmoClass mit durch den Aufruf der Singleton umgehen konnte [[MyGizmoClass alloc] init] statt [MyGizmoClass sharedManager]. Es wird festgehalten, weil + alloc erwartet wird, immer ein Objekt zurückgeben mit einem Beibehaltungszähler von +1.

Jeder Aufruf + alloc sollte mit einer -release oder -autorelease ausgeglichen werden, so dass ohne behält die in + allocWithZone :, die gemeinsamen Instanz möglicherweise unter anderen Benutzern freigegeben werden kann.

Sie können in einem einfachen, ein Verfahren, GCD-basierte Singleton-Implementierung (und damit 10.6+ nur) interessiert seine posted on Mike Ash Website :

+ (id)sharedFoo
{
    static dispatch_once_t pred;
    static Foo *foo = nil;

    dispatch_once(&pred, ^{ foo = [[self alloc] init]; });
    return foo;
}

Sie verweisen self in einer Klassenmethode! Big no-no! Zweitens fordern Sie [[self alloc] init] und nur die Instanz Wegwerfen. Sie sollten die Singleton-Referenz in der Klassenmethode zuweisen und nicht in init wie ich vermute, Sie tun. Als nächstes gibt es keine wirkliche Garantie, dass auf Null initialisiert wird _sharedMyClass. Sie sollten es auf nil explizit initialisieren.

static MyClass *_sharedMyClass = nil;

+ (MyClass *)sharedMyClass {
  @synchronized(self) {
    if (_sharedMyClass == nil)
      _sharedMyClass = [[MyClass alloc] init];
  }
  return _sharedMyClass;
}

Sie hatte auch wahrscheinlich diese dort zu ...

+ (id)allocWithZone:(NSZone *)zone {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
            return sharedInstance;  // assignment and return on first allocation
        }
    }
    return nil; // on subsequent allocation attempts return nil
}

Der Grund, warum Sie nicht waren es in init Speicherung ist, weil Sie es in dem Verfahren wurden die Speicherung, die aufgerufen Alloc. Dies ist das Muster Apple in ihren Beispielen hat. Wenn Sie den Wert in Ihrer init als auch speichern, ist alles in Ordnung und die Warnung geht weg. Ich würde die allocWithZone Umsetzung allein lassen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top