1001 * Является ли мое рассуждение верно, что нет ссылки цикла здесь?
Там нет ссылки цикла здесь. ViewController
не сохраняет обработчик завершения dataTask
. Вы можете думать об этом как о iOS, сохраняющем строгую ссылку как на контроллер представления, так и на обработчик завершения, а обработчик завершения также сохраняет строгую ссылку на контроллер представления. Не существует строгой ссылки от контроллера представления обратно на обработчик завершения или на какую-либо цепочку объектов со ссылкой на обработчик завершения, поэтому вы свободны от циклов. Ищите этот же шаблон в UIView.animate
, где вы снова отправляете замыкания в iOS вместо локального их хранения.
Для кратковременных операций приемлемо ли избегать [weak self]
?
Продолжительность работы не имеет значения. Два соответствующих вопроса:
- Существует ли цикл ссылок?
- Будет ли цикл ссылок нарушен?
Возьмите этот пример:
class BadVC: UIViewController {
private lazy var cycleMaker: () -> Void = { print(self) }
override func loadView() {
view = UIView()
cycleMaker()
}
}
BadVC
здесь удается создать ссылочный цикл, который никогда не будет прерван, как только он загрузит свое представление. Тот факт, что cycleMaker()
будет выполняться в наносекундах, не спасает нас от утечки памяти.
Прагматически, существует третий вопрос:
Позволяет ли этот код избежать постоянных эталонных циклов таким образом, чтобы его было трудно понять, легко сломать или ненадежно, так что эталонные циклы могут появиться в будущем из-за неправильного использования или модификации?
Вы можете разбить эталонные циклы вручную. Например:
class StillBadVC: UIViewController {
private lazy var cycleMaker: () -> Void = { print(self) }
override func loadView() {
view = UIView()
cycleMaker()
}
func breakCycle() {
cycleMaker = { }
}
}
Здесь мы находимся в опасности, потому что StillBadVC
имеет сильную ссылку на cycleMaker
, а cycleMaker
фиксирует сильную ссылку на StillBadVC
. Цикл будет прерван до тех пор, пока кто-нибудь не забудет вызвать breakCycle()
, после чего контроллер представления удалит свою сильную ссылку на cycleMaker
, что позволит cycleMaker
освободить место. Однако цикл будет не прерываться, если кто-то забудет позвонить breakCycle()
. Вызов метода с именем breakCycle()
обычно не является частью контракта на использование контроллера представления, поэтому мы ожидаем, что StillBadVC
приведет к утечкам памяти на практике.