Swift Language
Gestione della memoria
Ricerca…
introduzione
Unmanaged
] [1]. [1]: https://developer.apple.com/reference/swift/unmanaged
Osservazioni
Quando utilizzare la parola chiave weak:
La parola chiaveweak
deve essere utilizzata, se un oggetto di riferimento può essere deallocato durante la vita dell'oggetto che detiene il riferimento. Quando utilizzare la parola chiave sconosciuta:
Ilunowned
-parola chiave deve essere utilizzato, se un oggetto di riferimento non dovrebbe essere deallocato durante la vita dell'oggetto tiene il riferimento. insidie
Un errore frequente è quello di dimenticare di creare riferimenti agli oggetti, che sono necessari per sopravvivere al termine di una funzione, come i gestori di località, i gestori del movimento, ecc.Esempio:
class A : CLLocationManagerDelegate
{
init()
{
let locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
Questo esempio non funzionerà correttamente, in quanto il gestore di posizione viene deallocato dopo il ritorno dell'inizializzatore. La soluzione corretta è creare un riferimento forte come variabile di istanza:
class A : CLLocationManagerDelegate
{
let locationManager:CLLocationManager
init()
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
Cicli di riferimento e riferimenti deboli
Un ciclo di riferimento (o ciclo di mantenimento ) è così chiamato perché indica un ciclo nel grafico dell'oggetto :
Ogni freccia indica un oggetto che ne conserva un altro (un riferimento forte). A meno che il ciclo non venga interrotto, la memoria di questi oggetti non verrà mai liberata .
Un ciclo di conservazione viene creato quando due istanze di classi si richiamano l'una con l'altra:
class A { var b: B? = nil }
class B { var a: A? = nil }
let a = A()
let b = B()
a.b = b // a retains b
b.a = a // b retains a -- a reference cycle
Entrambe le istanze vivranno fino alla fine del programma. Questo è un ciclo di conservazione.
Riferimenti deboli
Per evitare i cicli di conservazione, utilizzare la parola chiave weak
o unowned
durante la creazione di riferimenti per interrompere i cicli di conservazione.
class B { weak var a: A? = nil }
I riferimenti deboli o non condivisi non aumentano il numero di riferimenti di un'istanza. Questi riferimenti non contribuiscono a mantenere i cicli. Il riferimento debole diventa nil
quando l'oggetto a cui fa riferimento viene deallocato.
a.b = b // a retains b
b.a = a // b holds a weak reference to a -- not a reference cycle
Quando si lavora con chiusure, è possibile utilizzare anche gli elenchi di acquisizione weak
e unowned
.
Gestione manuale della memoria
Quando si interfaccia con le API C, si potrebbe voler bloccare il contatore di riferimento Swift. Ciò avviene con oggetti non gestiti.
Se è necessario fornire un puntatore punteggiato a una funzione C, utilizzare il metodo toOpaque
della struttura Unmanaged
per ottenere un puntatore raw e fromOpaque
per ripristinare l'istanza originale:
setupDisplayLink() {
let pointerToSelf: UnsafeRawPointer = Unmanaged.passUnretained(self).toOpaque()
CVDisplayLinkSetOutputCallback(self.displayLink, self.redraw, pointerToSelf)
}
func redraw(pointerToSelf: UnsafeRawPointer, /* args omitted */) {
let recoveredSelf = Unmanaged<Self>.fromOpaque(pointerToSelf).takeUnretainedValue()
recoveredSelf.doRedraw()
}
Si noti che, se si utilizza passUnretained
e controparti, è necessario prendere tutte le precauzioni come con riferimenti unowned
citati.
Per interagire con API legacy Objective-C, è possibile che si desideri modificare manualmente il conteggio dei riferimenti di un determinato oggetto. Per questo Unmanaged
ha i rispettivi metodi di retain
e release
. Tuttavia, è più desiderabile utilizzare passRetained
e takeRetainedValue
, che eseguono il mantenimento prima di restituire il risultato:
func preferredFilenameExtension(for uti: String) -> String! {
let result = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension)
guard result != nil else { return nil }
return result!.takeRetainedValue() as String
}
Queste soluzioni dovrebbero essere sempre l'ultima risorsa e le API native della lingua potrebbero sempre essere preferite.