Middle
Como evitar a criação de um ciclo de retenção (retain cycle) no iOS?
sobes.tech IA
Resposta da IA
Os ciclos de retenção são evitados através do uso correto de referências fracas (weak) ou não retidas incondicionalmente (unowned).
Referências fracas (weak):
- Não aumentam o contador de referências do objeto.
- São nulas (podem tornar-se
nil). - Usadas quando um objeto pode existir independentemente de outro (por exemplo, um delegado).
class DelegateExample {
weak var delegate: SomeDelegateType? // Referência fraca ao delegado
}
Referências não retidas incondicionalmente (unowned):
- Não aumentam o contador de referências do objeto.
- Garantidamente não nulas.
- Usadas quando um objeto possui explicitamente outro, mas o objeto dependente só pode existir junto com o proprietário (por exemplo, closures capturando
selfnuma classe, onde a closure "pertence" explicitamente à instância da classe). Acesso a uma referênciaunownedquando o objeto já foi liberado causará um erro em tempo de execução.
class Owner {
var closure: (() -> Void)?
func setupClosure() {
closure = { [unowned self] in // Referência não retida incondicionalmente a self
// Uso de self
print("Usando self não retido")
}
}
}
Uso em closures:
Closures podem criar ciclos de retenção se capturam instâncias de classes por referência forte, e essa instância de classe também contém uma referência forte ao closure. Para evitar isso, usam-se listas de captura (capture lists) no início do closure:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { [weak self] in // Referência fraca a self
guard let strongSelf = self else {
return "" // Tratamento do caso em que self já é 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) está sendo desalocado")
}
}
A escolha entre weak e unowned depende da semântica das relações entre objetos:
weak: quando a referência pode tornar-senildurante o ciclo de vida do objeto referenciado.unowned: quando o objeto referenciado existe garantido por mais tempo ou igual ao objeto que o referencia, e a referência nunca seránil.