Denken Sie auch daran, dass Aufbewahrungszyklen auftreten können, wenn Ihr Block auf ein anderes Objekt verweist, das dann beibehalten wird self.
Ich bin nicht sicher, ob Garbage Collection bei diesen Aufbewahrungszyklen helfen kann. Wenn das Objekt, das den Block beibehält self(das ich das Serverobjekt nenne), überlebt (das Client-Objekt), wird der Verweis auf das selfInnere des Blocks erst dann als zyklisch betrachtet, wenn das Aufbewahrungsobjekt selbst freigegeben wird. Wenn das Serverobjekt seine Clients weit überlebt, liegt möglicherweise ein erheblicher Speicherverlust vor.
Da es keine sauberen Lösungen gibt, würde ich die folgenden Problemumgehungen empfehlen. Sie können auch eine oder mehrere auswählen, um Ihr Problem zu beheben.
- Verwenden Sie Blöcke nur zur Vervollständigung und nicht für offene Ereignisse. Verwenden Sie beispielsweise Blöcke für Methoden wie
doSomethingAndWhenDoneExecuteThisBlock:und nicht für Methoden wie setNotificationHandlerBlock:. Für die Fertigstellung verwendete Blöcke haben ein bestimmtes Lebensende und sollten von Serverobjekten freigegeben werden, nachdem sie ausgewertet wurden. Dies verhindert, dass der Haltezyklus zu lange lebt, selbst wenn er auftritt.
- Machen Sie diesen von Ihnen beschriebenen schwachen Referenztanz.
- Stellen Sie eine Methode zum Bereinigen Ihres Objekts bereit, bevor es freigegeben wird, mit der das Objekt von Serverobjekten "getrennt" wird, die möglicherweise Verweise darauf enthalten. und rufen Sie diese Methode auf, bevor Sie release für das Objekt aufrufen. Diese Methode ist zwar vollkommen in Ordnung, wenn Ihr Objekt nur einen Client hat (oder in einem bestimmten Kontext ein Singleton ist), bricht jedoch zusammen, wenn es mehrere Clients hat. Sie besiegen hier im Grunde den Retain-Counting-Mechanismus. das ist vergleichbar mit anrufen
deallocstatt release.
Wenn Sie ein Serverobjekt schreiben, nehmen Sie Blockargumente nur zur Vervollständigung. Akzeptieren Sie keine Blockargumente für Rückrufe wie z setEventHandlerBlock:. Greifen Sie stattdessen auf das klassische Delegatenmuster zurück: Erstellen Sie ein formales Protokoll und geben Sie eine setEventDelegate:Methode bekannt. Behalten Sie den Delegierten nicht. Wenn Sie nicht einmal ein formelles Protokoll erstellen möchten, akzeptieren Sie einen Selektor als Delegatenrückruf.
Und schließlich sollte dieses Muster Alarm auslösen:
- (nichtiger) Dealloc {
[myServerObject releaseCallbackBlocksForObject: self];
...
}}
Wenn Sie versuchen, Blöcke zu lösen, auf die selfvon innen verwiesen wird dealloc, sind Sie bereits in Schwierigkeiten. deallocMöglicherweise wird es aufgrund des durch Verweise im Block verursachten Aufbewahrungszyklus niemals aufgerufen. Dies bedeutet, dass Ihr Objekt einfach leckt, bis die Zuordnung des Serverobjekts aufgehoben wird.
selfProxies an,thisnur um die Dinge umzudrehen. In JavaScript nenne ich meinethisVerschlüsseself, damit es sich gut und ausgewogen anfühlt. :)