Когда в ARC (Swift) уменьшается счетчик сильных ссылок на объект?

Ответ

Счетчик сильных ссылок (retain count) уменьшается автоматически в следующих случаях:

  1. Когда переменная выходит из области видимости (например, завершается функция, в которой она была объявлена).
  2. Когда переменной присваивается nil или другой объект.
  3. Когда объект-владелец (например, массив или другой класс) деаллоцируется или удаляет ссылку.

Почему это важно? ARC освобождает память, как только счетчик достигает нуля, предотвращая утечки.

Пример:

class MyClass {
    deinit { print("Объект деаллоцирован") }
}

var strongRef1: MyClass? = MyClass() // Retain count = 1
var strongRef2 = strongRef1 // Retain count = 2 (присваивание)

strongRef1 = nil // Retain count = 1
strongRef2 = nil // Retain count = 0 -> вызывается deinit

Ключевой вывод: ARC управляет подсчетом автоматически, но разработчик должен избегать сильных циклических ссылок с помощью weak или unowned.

Ответ 18+ 🔞

Э, слушай, давай разберёмся с этим ARC, а то народ пугается, как чёрт ладана. Выглядит сложно, а на деле — хуй собачий, если вникнуть.

Вот представь: у тебя есть объект, и у него на шее висит бирочка — «retain count». Это типа счётчик, сколько ссылок на него смотрит. Каждая новая сильная ссылка — плюс один. Ну, как в пивнушке: чем больше друзей подсядет, тем дольше бутылка на столе стоит.

А теперь, внимание, ёпта, магия! Этот счётчик уменьшается сам, без твоего участия. Вот прям автоматом, как будто кто-то невидимый за тобой подтирает. И происходит это в трёх случаях, запоминай:

  1. Переменная сдохла в своей области видимости. Закончилась функция — и всё, пиши пропало. Ссылка исчезла, счётчик минус один. Красота.
  2. Ты приказал переменной: «Смотри в никуда!» То есть присвоил ей nil или другой объект. Она послушно отворачивается, и счётчик опять падает. Послушная сука.
  3. Какой-нибудь мощный владелец (массив там, или другой класс) сам откинулся или выкинул объект из себя. Ну, типа, «ты нам больше не друг». И снова — минус один в карму объекта.

А нахуя это всё? Да затем, блядь, чтобы память не текла, как решето! Как только счётчик доходит до нуля — ёбушки-воробушки — ARC хватает этот объект и выкидывает на свалку истории, вызывая deinit. Чистота, порядок, никакого мусора.

Смотри, как это выглядит в коде, тут всё просто:

class MyClass {
    deinit { print("Объект деаллоцирован") } // Прощальное письмо
}

var strongRef1: MyClass? = MyClass() // Создали. Retain count = 1. Один мужик в комнате.
var strongRef2 = strongRef1 // Дали на него ещё одну ссылку. Retain count = 2. Подселил соседа.

strongRef1 = nil // Первая ссылка сдохла. Retain count = 1. Первый мужик вышел покурить.
strongRef2 = nil // Вторая ссылка сдохла. Retain count = 0. Второй тоже ушёл.
// Комната пуста! ARC вызывает уборщицу (deinit) и печатает "Объект деаллоцирован".

И главная мысль, которую ты должен вынести, как хитрая жопа из поликлиники: ARC — он за тебя всё делает, это охуенно. Но! Если ты, мудак, накрутишь сильных ссылок по кругу (объект А ссылается на Б, а Б обратно на А), то они будут держать друг друга, как два пьяных друга у параши, и никогда не отпустят. Это и есть retain cycle, утечка памяти, пиздец.

Поэтому для таких случаев и придумали weak и unowned — это как сказать: «Я на тебя смотрю, но не держу». Вот и вся философия.