cat swift/arc-ownership-automatica.md
ARC: ownership automatica ma non invisibile
Automatic Reference Counting gestisce la memoria delle classi, ma il programmatore deve capire chi possiede cosa.
Swift usa ARC, Automatic Reference Counting, per gestire la memoria degli oggetti class.
Automatico non significa magico. ARC libera un oggetto quando non esistono più riferimenti forti a quell’oggetto. Se i riferimenti forti formano un ciclo, l’oggetto può restare vivo per sempre.
Riferimenti forti
Per default, una proprietà che punta a una classe mantiene un riferimento forte.
final class Cliente {
let nome: String
init(nome: String) {
self.nome = nome
}
deinit {
print("Cliente rilasciato")
}
}
var cliente: Cliente? = Cliente(nome: "Ada")
cliente = nil
Quando cliente diventa nil, se non ci sono altri riferimenti forti, l’oggetto viene rilasciato e deinit viene chiamato.
Ownership: chi possiede chi
Il punto importante è ragionare in termini di possesso.
final class OrdineCoordinator {
let sessione: SessioneCheckout
init(sessione: SessioneCheckout) {
self.sessione = sessione
}
}
Il coordinator possiede la sessione? Se si, il riferimento forte è sensato.
Se invece una relazione è solo osservazione o collegamento inverso, un riferimento forte può essere sbagliato.
deinit come strumento didattico
deinit viene chiamato quando un’istanza di classe sta per essere rilasciata.
final class Tracker {
deinit {
print("Tracker deinit")
}
}
Non riempire il codice di produzione di print in deinit, ma in laboratorio è utile per capire se un oggetto viene liberato.
Struct e ARC
ARC riguarda principalmente le classi. Una struct non ha reference counting proprio come oggetto.
Ma una struct può contenere riferimenti:
struct Schermata {
let viewModel: CheckoutViewModel
}
Se CheckoutViewModel è una classe, quel riferimento è gestito da ARC.
Riferimenti temporanei
var a: Cliente? = Cliente(nome: "Ada")
var b = a
a = nil
L’oggetto non viene rilasciato, perché b lo mantiene ancora.
b = nil
Ora può essere rilasciato.
Questo è reference counting: conta quanti riferimenti forti mantengono vivo l’oggetto.
ARC non risolve cicli
Se A mantiene B e B mantiene A, il conteggio non arriva mai a zero.
final class Utente {
var carrello: CarrelloSessione?
}
final class CarrelloSessione {
var utente: Utente?
}
Se entrambi sono riferimenti forti, hai un potenziale ciclo.
La prossima lezione entra nel dettaglio di weak e unowned.
Quando usare classi con più attenzione
Ogni volta che introduci una classe, chiediti:
- chi la possiede?
- quanto deve vivere?
- chi può mantenerla viva?
- esistono riferimenti inversi?
- una closure la cattura?
- serve davvero identità condivisa?
Queste domande evitano gran parte dei problemi ARC.
ARC e performance
Gestire reference count ha un costo. Di solito non è un problema, ma in codice molto caldo può contare.
Questo non significa evitare tutte le classi. Significa:
- non creare oggetti inutili in loop critici;
- preferire value types quando bastano;
- evitare architetture piene di piccoli oggetti mutabili senza motivo.
Checklist
Con ARC ricorda:
- le classi sono gestite da reference counting;
- i riferimenti sono forti per default;
- un oggetto viene liberato quando non ha più riferimenti forti;
deinitaiuta a osservare il rilascio;- i cicli forti non vengono risolti automaticamente;
- ownership va progettata.
Esercizio
Crea due classi:
CheckoutViewModel;CouponRepositoryInMemoria.
Aggiungi deinit a entrambe. Crea e rilascia istanze opzionali, osservando quando vengono liberate.
Poi aggiungi un riferimento da una all’altra e spiega chi possiede chi.