Dealloc in Swift

145

Ich möchte am Ende des Lebens eines View Controllers eine Bereinigung durchführen, nämlich eine NSNotificationCenterBenachrichtigung entfernen . Das Implementieren deallocführt zu einem Swift-Compilerfehler:

Cannot override 'dealloc' which has been marked unavailable

Was ist die bevorzugte Methode, um am Ende des Lebens eines Objekts in Swift eine Bereinigung durchzuführen?

Kyle Clegg
quelle

Antworten:

333
deinit {
    // perform the deinitialization
}

Aus der Swift-Dokumentation :

Ein Deinitializer wird unmittelbar vor der Freigabe einer Klasseninstanz aufgerufen. Sie schreiben Deinitializer mit dem Schlüsselwort deinit, ähnlich wie Intializer mit dem Schlüsselwort init geschrieben werden. Deinitializer sind nur für Klassentypen verfügbar.

Normalerweise müssen Sie keine manuelle Bereinigung durchführen, wenn Ihre Instanzen freigegeben werden. Wenn Sie jedoch mit Ihren eigenen Ressourcen arbeiten, müssen Sie möglicherweise selbst eine zusätzliche Bereinigung durchführen. Wenn Sie beispielsweise eine benutzerdefinierte Klasse erstellen, um eine Datei zu öffnen und Daten in diese zu schreiben, müssen Sie die Datei möglicherweise schließen, bevor die Zuordnung der Klasseninstanz aufgehoben wird.

Kyle Clegg
quelle
45
deinit {
    // perform the deinitialization
}

ist die richtige Antwort für Swift "Dealloc".

Es ist jedoch gut, in iOS 9 neu darauf hinzuweisen, dass NSNotificationCenter nicht mehr bereinigt werden muss!

https://developer.apple.com/library/content/releasenotes/Foundation/RN-FoundationOlderNotes/index.html#X10_11Notes

NSNotificationCenter

In OS X 10.11 und iOS 9.0 senden NSNotificationCenter und NSDistributedNotificationCenter keine Benachrichtigungen mehr an registrierte Beobachter, die möglicherweise freigegeben werden. Wenn der Beobachter als Referenz mit schwacher Nullung gespeichert werden kann, speichert der zugrunde liegende Speicher den Beobachter als Referenz mit schwacher Nullung. Alternativ kann das Objekt nicht schwach gespeichert werden (dh es verfügt über einen benutzerdefinierten Aufbewahrungs- / Freigabemechanismus, der die Laufzeit verhindert Wenn das Objekt nicht schwach gespeichert werden kann, wird es als nicht schwache Nullpunktreferenz gespeichert. Dies bedeutet, dass Beobachter sich bei ihrer Freigabemethode nicht abmelden müssen. Die nächste Benachrichtigung, die an diesen Beobachter weitergeleitet wird, erkennt die auf Null gesetzte Referenz und hebt die Registrierung des Beobachters automatisch auf. Wenn auf ein Objekt nur schwach verwiesen werden kann, werden während der Freigabe keine Benachrichtigungen mehr an den Beobachter gesendet. Das bisherige Verhalten beim Empfang von Benachrichtigungen während des Deallocs ist bei nicht schwach auf Null stehenden Referenzbeobachtern weiterhin vorhanden. Blockbasierte Beobachter über die Methode - [NSNotificationCenter addObserverForName: object: queue: usingBlock] müssen noch abgemeldet werden, wenn sie nicht mehr verwendet werden, da das System immer noch einen starken Verweis auf diese Beobachter enthält. Das vorzeitige Entfernen von Beobachtern (entweder schwach referenziert oder auf null bezogen) wird weiterhin unterstützt. CFNotificationCenterAddObserver entspricht diesem Verhalten nicht, da der Beobachter möglicherweise kein Objekt ist. Blockbasierte Beobachter über die Methode - [NSNotificationCenter addObserverForName: object: queue: usingBlock] müssen noch abgemeldet werden, wenn sie nicht mehr verwendet werden, da das System immer noch einen starken Verweis auf diese Beobachter enthält. Das vorzeitige Entfernen von Beobachtern (entweder schwach referenziert oder auf null bezogen) wird weiterhin unterstützt. CFNotificationCenterAddObserver entspricht diesem Verhalten nicht, da der Beobachter möglicherweise kein Objekt ist. Blockbasierte Beobachter über die Methode - [NSNotificationCenter addObserverForName: object: queue: usingBlock] müssen noch abgemeldet werden, wenn sie nicht mehr verwendet werden, da das System immer noch einen starken Verweis auf diese Beobachter enthält. Das vorzeitige Entfernen von Beobachtern (entweder schwach referenziert oder auf null bezogen) wird weiterhin unterstützt. CFNotificationCenterAddObserver entspricht diesem Verhalten nicht, da der Beobachter möglicherweise kein Objekt ist.

Beachten Sie jedoch die folgenden Punkte zu starken Referenzen, sodass Sie sich möglicherweise trotzdem um die Bereinigung kümmern müssen ...?

James
quelle
3
Sofern der Benachrichtigungsblock keine starke Referenz enthält, müssen Sie den Beobachter entfernen.
TigerCoding
+1, weil Beobachter nicht aufgeräumt werden müssen. Wichtig zu wissen! Ich mache alle Erfassungsreferenzen schwach, damit ich mich nie damit befassen muss.
n13
2
Benachrichtigungsblöcke scheinen laut Dokumentation immer stark referenziert zu sein. Also: Wenn Sie Blöcke verwenden, um Ihre Benachrichtigungen zu verarbeiten, müssen Sie die Registrierung innerhalb von deinit aufheben.
Marsbear
22

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Deinitialization.html

Swift gibt Ihre Instanzen automatisch frei, wenn sie nicht mehr benötigt werden, um Ressourcen freizugeben. Swift übernimmt die Speicherverwaltung von Instanzen durch automatische Referenzzählung (ARC), wie unter Automatische Referenzzählung beschrieben. Normalerweise müssen Sie keine manuelle Bereinigung durchführen, wenn Ihre Instanzen freigegeben werden. Wenn Sie jedoch mit Ihren eigenen Ressourcen arbeiten, müssen Sie möglicherweise selbst eine zusätzliche Bereinigung durchführen. Wenn Sie beispielsweise eine benutzerdefinierte Klasse erstellen, um eine Datei zu öffnen und Daten in diese zu schreiben, müssen Sie die Datei möglicherweise schließen, bevor die Zuordnung der Klasseninstanz aufgehoben wird.

Klassendefinitionen können höchstens einen Deinitialisierer pro Klasse haben. Der Deinitializer akzeptiert keine Parameter und wird ohne Klammern geschrieben:

deinit {
    // perform the deinitialization
}
Varsha Vijayvargiya
quelle
2

Das Entfernen des Beobachters ist vor der Freigabe erforderlich, da sonst ein Absturz auftreten würde. Dies kann mit erfolgen

deinit {
    // perform the deinitialization
    print("deinit")

    removeObserver(self, forKeyPath: kSelectedViewControllerKey, context: nil)
    removeObserver(self, forKeyPath: kSelectedIndexKey, context: nil)

}
Spydy
quelle
-2

Seien Sie vorsichtig, wenn Sie eine Methode in einer anderen Klasse von deinit aufrufen , da dies wahrscheinlich zum Absturz führen wird

Jeba Moses
quelle
1
Eine Abwertung sollte nicht unbedingt der Fall sein. Aus ref. docs : Da eine Instanz erst freigegeben wird, nachdem ihr Deinitializer aufgerufen wurde, kann ein Deinitializer auf alle Eigenschaften der Instanz zugreifen, auf die er aufgerufen wird, und sein Verhalten basierend auf diesen Eigenschaften ändern (z. B. den Namen einer Datei nachschlagen, die benötigt wird geschlossen).
Superjos