dealloc in Swift


145

Vorrei eseguire un po 'di pulizia alla fine della vita di un controller di visualizzazione, in particolare per rimuovere una NSNotificationCenternotifica. L'implementazione deallocrisulta in un errore del compilatore Swift:

Cannot override 'dealloc' which has been marked unavailable

Qual è il modo preferito per eseguire una pulizia alla fine della vita di un oggetto in Swift?

Risposte:


333
deinit {
    // perform the deinitialization
}

Dalla documentazione Swift :

Un deinizializzatore viene chiamato immediatamente prima che un'istanza di classe venga deallocata. Scrivi deinizializzatori con la parola chiave deinit, in modo simile a come vengono scritti gli inizializzatori con la parola chiave init. I deinizializzatori sono disponibili solo per i tipi di classe.

In genere non è necessario eseguire la pulizia manuale quando le istanze sono deallocate. Tuttavia, quando si lavora con le proprie risorse, potrebbe essere necessario eseguire personalmente qualche ulteriore pulizia. Ad esempio, se si crea una classe personalizzata per aprire un file e scrivere alcuni dati su di esso, potrebbe essere necessario chiudere il file prima che l'istanza della classe venga deallocata.


45
deinit {
    // perform the deinitialization
}

è la risposta corretta per Swift "dealloc".

Tuttavia, è bene sottolineare che in iOS 9 è nuovo che NSNotificationCenter non ha più bisogno di essere ripulito!

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

NSNotificationCenter

In OS X 10.11 e iOS 9.0 NSNotificationCenter e NSDistributedNotificationCenter non invieranno più notifiche agli osservatori registrati che potrebbero essere deallocate. Se l'osservatore è in grado di essere archiviato come riferimento debole di azzeramento, la memoria sottostante memorizzerà l'osservatore come riferimento debole di azzeramento, in alternativa se l'oggetto non può essere archiviato debolmente (cioè ha un meccanismo di conservazione / rilascio personalizzato che impedirebbe il runtime dalla possibilità di memorizzare l'oggetto in modo debole) memorizzerà l'oggetto come riferimento di azzeramento non debole. Ciò significa che gli osservatori non sono tenuti ad annullare la registrazione nel loro metodo di deallocazione. La notifica successiva che verrebbe indirizzata a quell'osservatore rileverà il riferimento azzerato e annullerà automaticamente la registrazione dell'osservatore. Se un oggetto può avere un riferimento debole, le notifiche non verranno più inviate all'osservatore durante la deallocazione; il precedente comportamento di ricevere le notifiche durante il dealloc è ancora presente nel caso di osservatori di riferimento che non azzerano debolmente. Gli osservatori basati su blocchi tramite il metodo - [NSNotificationCenter addObserverForName: object: queue: usingBlock] devono ancora essere non registrati quando non sono più in uso poiché il sistema conserva ancora un forte riferimento a questi osservatori. La rimozione prematura degli osservatori (con riferimenti deboli o azzerati) è ancora supportata. CFNotificationCenterAddObserver non è conforme a questo comportamento poiché l'osservatore potrebbe non essere un oggetto. Gli osservatori basati su blocchi tramite il metodo - [NSNotificationCenter addObserverForName: object: queue: usingBlock] devono ancora essere non registrati quando non sono più in uso poiché il sistema conserva ancora un forte riferimento a questi osservatori. La rimozione prematura degli osservatori (con riferimenti deboli o azzerati) è ancora supportata. CFNotificationCenterAddObserver non è conforme a questo comportamento poiché l'osservatore potrebbe non essere un oggetto. Gli osservatori basati su blocchi tramite il metodo - [NSNotificationCenter addObserverForName: object: queue: usingBlock] devono ancora essere non registrati quando non sono più in uso poiché il sistema conserva ancora un forte riferimento a questi osservatori. La rimozione prematura degli osservatori (con riferimenti deboli o azzerati) è ancora supportata. CFNotificationCenterAddObserver non è conforme a questo comportamento poiché l'osservatore potrebbe non essere un oggetto.

ma nota i punti seguenti sui riferimenti forti, quindi potresti doverti preoccupare della pulizia comunque ...?


3
A meno che il blocco di notifica non abbia un riferimento sicuro, è necessario rimuovere l'osservatore.
TigerCoding

+1 per non dover ripulire gli osservatori. Importante da sapere! Rendo deboli tutti i riferimenti di acquisizione, quindi non devo mai occuparmene.
n13,

2
I blocchi di notifica sembrano sempre essere fortemente referenziati in base alla documentazione. Quindi: se si utilizzano blocchi per gestire le notifiche, è necessario annullare la registrazione per loro all'interno di Deinit.
Marsbear

22

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

Swift disloca automaticamente le istanze quando non sono più necessarie per liberare risorse. Swift gestisce la gestione della memoria delle istanze tramite il conteggio dei riferimenti automatico (ARC), come descritto nel conteggio dei riferimenti automatico. In genere non è necessario eseguire la pulizia manuale quando le istanze sono deallocate. Tuttavia, quando si lavora con le proprie risorse, potrebbe essere necessario eseguire personalmente qualche ulteriore pulizia. Ad esempio, se si crea una classe personalizzata per aprire un file e scrivere alcuni dati su di esso, potrebbe essere necessario chiudere il file prima che l'istanza della classe venga deallocata.

Le definizioni di classe possono avere al massimo un deinizializzatore per classe. Il deinizializzatore non accetta alcun parametro ed è scritto senza parentesi:

deinit {
    // perform the deinitialization
}

2

la rimozione dell'osservatore è necessaria prima della deallocazione, altrimenti si verifica un arresto anomalo. Si può fare usando

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

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

}

-2

Fai attenzione quando chiami un metodo in un'altra classe da deinit probabilmente finirà in crash


1
Sottovalutato in quanto non dovrebbe essere necessariamente il caso. Dal rif. documenti : poiché un'istanza non viene deallocata fino a quando non viene chiamato il suo deinizializzatore, un deinizializzatore può accedere a tutte le proprietà dell'istanza su cui viene chiamato e può modificare il suo comportamento in base a tali proprietà (come cercare il nome di un file che deve essere chiuso).
Superjos,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.