Может ли один объект с сильной (strong) ссылкой создать утечку памяти?

«Может ли один объект с сильной (strong) ссылкой создать утечку памяти?» — вопрос из категории Управление памятью, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, может. Это происходит при образовании цикла сильных ссылок (strong reference cycle или retain cycle), когда два или более объекта удерживают друг друга через strong ссылки. Автоматический подсчет ссылок (ARC) не может освободить такие объекты, так как счетчик каждого из них никогда не становится равным нулю.

Пример цикла:

class Person {
    var apartment: Apartment? // Strong ссылка
}

class Apartment {
    var tenant: Person? // Strong ссылка -> ЦИКЛ!
}

var john: Person? = Person()
var unit4A: Apartment? = Apartment()

john!.apartment = unit4A
unit4A!.tenant = john // Образовался цикл сильных ссылок

john = nil    // Счетчик Person? = 1 (удерживается unit4A.tenant)
unit4A = nil  // Счетчик Apartment? = 1 (удерживается john?.apartment)
// ОБА ОБЪЕКТА НИКОГДА НЕ ОСВОБОЖДАЮТСЯ -> УТЕЧКА ПАМЯТИ.

Решение: Разорвать цикл, заменив одну из сильных ссылок на weak или unowned.

class Apartment {
    weak var tenant: Person? // Weak ссылка не увеличивает retain count
}
// Теперь при john = nil объект Person будет освобожден,
// после чего apartment?.tenant станет nil, и объект Apartment также освободится.
  • weak: Используется, когда ссылка может стать nil (опциональный тип).
  • unowned: Используется, когда ссылка всегда должна иметь значение, но не должна удерживать объект (например, для родительских объектов).