> Какую ссылку лучше делать слабой в цикле сильных ссылок и почему (iOS, Swift)

Уровень: senior · Роль: mobile · Категория: Технические вопросы

Компании: Тинькофф

Стек: iOS, Swift

> Пример ответа

Короткий ответ

В цикле сильных ссылок слабой делают ссылку на объект с меньшим временем жизни или на тот, который логически не должен удерживать другой объект. Обычно это ссылка на делегата, замыкание или дочерний объект, который ссылается на родителя. Слабая ссылка разрывает цикл, позволяя ARC корректно освободить память, когда объект больше не нужен.

Подробное объяснение

Цикл сильных ссылок возникает, когда два объекта ссылаются друг на друга через strong свойства. ARC не может освободить ни один из них, так как retain count каждого не падает до нуля. Чтобы разорвать цикл, одна из ссылок должна быть weak или unowned.

Выбор, какую ссылку делать слабой, зависит от иерархии владения:

  • Владелец должен иметь сильную ссылку на зависимый объект. Например, ViewController сильно держит View, но View не должен сильно держать ViewController.
  • Объект с более коротким жизненным циклом не должен удерживать объект с более длинным. Если один объект может быть уничтожен раньше другого, ссылка на "долгоживущий" объект должна быть слабой.
  • Делегаты и data source всегда делают слабыми, чтобы избежать retain cycle между UITableView и UIViewController, который её реализует.
  • Замыкания захватывают self слабо, если они хранятся в свойстве объекта, иначе возникает цикл: объект → замыкание → объект.

Правило простое: слабой делают ссылку на объект, который не является владельцем в данной паре. Владелец - тот, кто создаёт и управляет жизненным циклом другого объекта. Если оба претендуют на владение, это архитектурная ошибка.

На практике

В iOS-разработке типичные сценарии:

  • Delegate pattern: UITableView имеет weak var delegate. Делегат (обычно UIViewController) сильно держит таблицу, таблица слабо держит делегата. Если сделать наоборот - цикл.
  • Closure capture: если замыкание хранится в свойстве объекта и внутри обращается к self, используй [weak self]. Иначе объект и замыкание будут удерживать друг друга.
  • Parent-child relationship: дочерний объект хранит weak var parent, родитель хранит strong var child. Ребёнок не должен удерживать родителя - родитель может быть уничтожен, и ребёнок должен это пережить.
  • Observer pattern: подписчик хранит слабую ссылку на наблюдаемый объект, если не хочет продлевать его жизнь.

Пример кода

SWIFT
class Parent {
var child: Child?
}
class Child {
weak var parent: Parent? // слабая ссылка на родителя
}
// Замыкание
class ViewModel {
var onUpdate: (() -> Void)?
func configure() {
onUpdate = { [weak self] in
self?.doSomething()
}
}
func doSomething() { }
}

Как отвечать на собеседовании

Начни с определения цикла сильных ссылок и роли ARC. Затем объясни, что слабой делают ссылку на объект, который не является владельцем, либо на объект с более коротким временем жизни. Приведи 2-3 конкретных примера: delegate, closure, parent-child. Подчеркни, что weak всегда optional, а unowned - для случаев, когда объект гарантированно жив. Если спросят про unowned, уточни, что он опасен при обращении после освобождения объекта.

Что проверяет интервьюер

  • Понимание ARC и механизма retain count.
  • Умение анализировать граф владения объектами.
  • Знание паттернов iOS: delegate, closure capture, observer.
  • Способность объяснить trade-off между weak и unowned.
  • Понимание жизненного цикла объектов в UIKit/SwiftUI.

Типичные ошибки

  • Делать слабой ссылку на владельца (например, weak var tableView в делегате - ошибка, таблица должна быть сильной).
  • Использовать unowned без уверенности в времени жизни объекта - риск crash.
  • Забывать [weak self] в замыканиях, хранимых в свойствах.
  • Делать обе ссылки слабыми - тогда объекты могут быть освобождены преждевременно.
  • Путать weak и unowned: weak допускает nil, unowned - нет.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью