Справочный цикл в Swift
Управление памятью для разработчика обычно нетривиально. Благодаря автоматическому подсчету ссылок (ARC) разработчики iOS упрощают управление памятью. Он просто работает большую часть времени. Однако эталонный цикл очень сложен, и я видел, как многие опытные разработчики допускают такие ошибки.
Официальная документация в основном говорит о базовом цикле ссылок между двумя объектами A<->B. В этой статье я собираюсь показать эталонный цикл среди 3 или 4 объектов, который труднее обнаружить.
Приложение с утечкой памяти
Демонстрация представляет собой очень простой проект iOS с двумя экранами. На первом экране «InitialViewController» пользователь может нажать кнопку, чтобы запустить второй экран «SampleViewController», затем пользователь может нажать кнопку закрытия, чтобы закрыть второй экран. Второй экран закодирован с использованием чистой архитектуры VIP.
В то время как пользователю нравится использовать приложение, память утекает. На следующем экране из функции «Debug Memory Graph» Xcode мы видим, что произошла утечка 5 экземпляров каждого из «SampleViewController», «SamplePresenter», «SampleInteractor» и «SampleRouter». Когда слишком много памяти утечет, приложение будет уничтожено системой, что будет очень неловко для разработчика приложения.
Ссылочный цикл в нескольких объектах
Давайте внимательно посмотрим на исходный код ниже, чтобы выяснить, почему происходит утечка памяти.
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
}
На самом деле в нем два эталонных цикла:
- Interactor->Presenter->ViewController->Interactor
- Interactor-> Presenter-> Router -> ViewController-> Interactor
Чтобы решить эту проблему, мы можем использовать слабую ссылку, как показано ниже.
Затем у нас больше нет эталонного цикла для VIP в соответствии со следующей диаграммой.
Справочный цикл, связанный с захватом блока
Ху! Это здорово, потому что мы только что исправили два эталонных цикла, но мы еще не закончили. Если вы запустите приложение сейчас, вы увидите, что у нас все еще есть утечки памяти. Причиной является следующая часть кода.
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()
}
// ...
}
}
Как только мы узнаем, в чем проблема, исправить ее несложно, см. Ниже.
Краткое содержание
Подводя итог, мы рассмотрели два типа циклов ссылок, которые происходят внутри нескольких объектов. Вы можете найти демонстрационный проект здесь , а исправление было подготовлено в запросе на слияние для вашего удобства. Надеюсь, что эта статья поможет вам лучше понять справочный цикл и избежать его.

![В любом случае, что такое связанный список? [Часть 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































