Middle
Come prevenire la creazione di un ciclo di ritenzione (retain cycle) in iOS?
sobes.tech AI
Risposta dell'AI
I cicli di ritenzione vengono evitati mediante l'uso corretto di riferimenti deboli (weak) o non trattenuti incondizionatamente (unowned).
Riferimenti deboli (weak):
- Non aumentano il contatore di riferimenti dell'oggetto.
- Sono nullable (possono diventare
nil). - Sono usate quando un oggetto può esistere indipendentemente da un altro (ad esempio, un delegato).
class DelegateExample {
weak var delegate: SomeDelegateType? // Riferimento debole al delegato
}
Riferimenti non trattenuti incondizionatamente (unowned):
- Non aumentano il contatore di riferimenti dell'oggetto.
- Sono garantiti non nulli.
- Sono usati quando un oggetto possiede esplicitamente un altro, ma l'oggetto dipendente può esistere solo insieme al proprietario (ad esempio, chiusure che catturano
selfin una classe, dove la chiusura "appartiene" esplicitamente all'istanza della classe). Accedere a una referenzaunownedquando l'oggetto è già stato deallocato causerà un errore in fase di esecuzione.
class Owner {
var closure: (() -> Void)?
func setupClosure() {
closure = { [unowned self] in // Riferimento non trattenuto incondizionatamente a self
// Uso di self
print("Utilizzo di self non trattenuto")
}
}
}
Utilizzo nei closure:
I closure possono creare cicli di ritenzione se catturano istanze di classi con riferimenti forti, e questa istanza di classe contiene anche un riferimento forte al closure. Per evitarlo, si usano le liste di cattura (capture lists) all'inizio del closure:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { [weak self] in // Riferimento debole a self
guard let strongSelf = self else {
return "" // Gestione del caso in cui self è già nil
}
if let text = strongSelf.text {
return "<\(strongSelf.name)>\(text)</\(strongSelf.name)>"
} else {
return "<\(strongSelf.name)/>"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) viene deallocato")
}
}
La scelta tra weak e unowned dipende dalla semantica delle relazioni tra gli oggetti:
weak: quando la referenza può diventarenildurante il ciclo di vita dell'oggetto referenziato.unowned: quando l'oggetto referenziato esiste garantito più a lungo o uguale a quello che lo riferisce, e la referenza non diventerà mainil.