Ricerca…


introduzione

Questo argomento descrive come e quando il runtime di Swift deve allocare memoria per le strutture di dati dell'applicazione e quando tale memoria deve essere recuperata. Per impostazione predefinita, le istanze della classe di supporto della memoria vengono gestite tramite il conteggio dei riferimenti. Le strutture sono sempre passate attraverso la copia. Per disattivare lo schema di gestione della memoria integrato, si potrebbe usare la struttura [ Unmanaged ] [1]. [1]: https://developer.apple.com/reference/swift/unmanaged

Osservazioni

Quando utilizzare la parola chiave weak:

La parola chiave weak 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:

Il unowned -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 :

mantenere il ciclo

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.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow