Ciclo de referência em Swift
O gerenciamento de memória para um desenvolvedor geralmente não é trivial. Graças à Contagem Automática de Referência (ARC), o gerenciamento de memória é facilitado para desenvolvedores iOS. Apenas funciona na maioria das vezes. No entanto, o ciclo de referência é muito complicado e já vi muitos desenvolvedores experientes cometerem esses erros.
A documentação oficial fala principalmente sobre o ciclo básico de referência entre dois objetos A<->B. O que vou mostrar neste artigo é o ciclo de referência entre 3 ou 4 objetos, o que é mais difícil de detectar.
O aplicativo com vazamento de memória
A demonstração é um projeto iOS muito simples com duas telas. Na primeira tela “InitialViewController”, o usuário pode clicar no botão para iniciar a segunda tela “SampleViewController”, então o usuário pode clicar no botão Fechar para fechar a segunda tela. A segunda tela é codificada usando a arquitetura limpa VIP.
Enquanto o usuário gosta de usar o App, a memória está vazando para trás. Na tela a seguir do recurso “Debug Memory Graph” do Xcode, podemos ver que 5 instâncias de cada um de “SampleViewController”, “SamplePresenter”, “SampleInteractor” e “SampleRouter” vazaram. Quando muita memória vazar, o aplicativo será encerrado pelo sistema, o que será muito embaraçoso para o desenvolvedor do aplicativo.
Ciclo de Referência em Vários Objetos
Vamos dar uma olhada no código-fonte abaixo para descobrir por que o vazamento de memória.
class SampleViewController: UIViewController, SampleViewControllerInterface {
var interactor: SampleInteractorInterface?
// omitted the rest for simplicity
}
class SampleInteractor: SampleInteractorInterface {
var presenter: SamplePresenterInterface?
// omitted the rest for simplicity
}
class SamplePresenter: SamplePresenterInterface {
var viewController: SampleViewControllerInterface?
var router: SampleRouterInterface?
// omitted the rest for simplicity
}
class SampleRouter: SampleRouterInterface {
var viewController: UIViewController?
// omitted the rest for simplicity
}
Na verdade, existem dois ciclos de referência nele:
- Interator->Apresentador->ViewController->Interator
- Interator->Apresentador->Router ->ViewController->Interactor
Para resolvê-lo, podemos usar uma referência fraca como a alteração abaixo.
Então, não temos mais um ciclo de referência para VIP conforme o diagrama a seguir.
Ciclo de Referência Relacionado à Captura de Bloco
Hoo! Isso é ótimo porque acabamos de fixar dois ciclos de referência, mas ainda não terminamos. Se você executar o aplicativo agora, verá que ainda temos vazamentos de memória. A causa é a seguinte parte do código.
class CustomButton: UIView {
var buttonClickHander: (() -> Void)?
// omitted the rest for simplicity
}
class SampleViewController: UIViewController, SampleViewControllerInterface {
private lazy var customButton: CustomButton = {
let button = CustomButton()
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
private func setUpUI() {
view.addSubview(customButton)
customButton.buttonClickHander = {
self.interactor?.customButtonClicked()
}
// ...
}
}
Uma vez que sabemos onde está o problema, corrigi-lo é simples, veja abaixo.
Resumo
Resumindo, cobrimos dois tipos de ciclos de referência que ocorrem em vários objetos. Você pode encontrar o projeto de demonstração aqui , e a correção foi preparada em uma solicitação pull para sua fácil revisão. Espero que este artigo ajude você a entender melhor o ciclo de referência e a ter confiança para evitá-lo.





































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)