Ответ
ARC (Automatic Reference Counting) автоматически вставляет вызовы retain и release, отслеживая время жизни сильных (strong) ссылок на объекты.
Правила вставки:
retain: Вставляется при присваивании объекта сильной ссылке (переменной, свойству, константе). Увеличивает счетчик ссылок.release: Вставляется в двух случаях:- Когда сильная ссылка перезаписывается другим значением (или
nil). - Когда сильная ссылка выходит из области видимости (например, завершается функция).
- Когда сильная ссылка перезаписывается другим значением (или
Пример трассировки:
class MyClass {}
func example() {
// Область видимости начинается
var obj1: MyClass? = MyClass() // ARC: retain для нового объекта
var obj2: MyClass? = obj1 // ARC: retain (присваивание obj1 в obj2)
obj1 = nil // ARC: release для obj1
// Объект еще жив, так как на него ссылается obj2
obj2 = MyClass() // ARC: release для старого объекта, retain для нового
// Старый объект уничтожается здесь (счетчик = 0)
} // ARC: release для obj2 (для нового объекта) при выходе из области видимости
Особые случаи:
weakссылки: Не вызываютretain, поэтому не влияют на счетчик. ARC автоматически обнуляет (nil)weak-переменную послеreleaseпоследней сильной ссылки.unownedссылки: Также не вызываютretain, но не обнуляются. Ответственность за обеспечение времени жизни объекта лежит на программисте.- Циклы сильных ссылок: ARC не может их разорвать, что приводит к утечкам памяти. Решение — использование
weakилиunowned.
Ответ 18+ 🔞
Да ты посмотри на эту магию, блядь! ARC — это ж как домовой в твоём коде, сука, только вместо того, чтобы носки воровать, он за тобой retain и release раскидывает, чтобы память не текла, как из дырявого ведра.
Вот смотри, как этот хитрожопый компилятор работает. Берёт он твой красивый Swift-код и начинает туда, внатуре, свои пасхалки вставлять.
Где он что суёт:
retain: Впендюривается ровно в тот момент, когда ты какую-нибудь переменную, этого, сильную, блядь, нацеливаешь на свежеиспечённый объект. Счётчик ссылок — раз! — и подрос, ёпта.release: А вот эта пакость лезет в двух случаях, когда тебя подловить можно:- Когда ты свою же сильную ссылку, неблагодарная тварь, переписываешь на другую (или на
nil). - Когда переменная, сука, выходит из области видимости — типа функция кончилась, и всё, пиши пропало.
- Когда ты свою же сильную ссылку, неблагодарная тварь, переписываешь на другую (или на
Разбор полётов, на живом примере:
class MyClass {}
func example() {
// Заходим в зону, блядь, ответственности
var obj1: MyClass? = MyClass() // ARC: тихо ебёт retain на новый объект
var obj2: MyClass? = obj1 // ARC: и ещё один retain, потому что obj2 тоже на него смотрит
obj1 = nil // ARC: а тут release для obj1! Но объект жив, ёпта, его же obj2 держит!
obj2 = MyClass() // ARC: ой-вей! Сначала release для старого объекта (счётчик в ноль — ему пиздец), потом retain для нового.
// Старичка тут и прикончили, блядь, память освободили.
} // ARC: а на выходе из функции — бац! — ещё release для obj2, уже по новому объекту.
А теперь, блядь, тонкости, где можно обосраться:
weakссылки: Это как смотреть на чужую пиццу, блядь. Ты на неё смотришь (weak), но взять не можешь (retainне вызывается). И как только последний жадный едок (сильная ссылка) доедает свой кусок, тебе так вежливо говорят: «Всё, пиццы нет, иди нахуй» — и твояweak-переменная становитсяnil.unownedссылки: А это, сука, как по тонкому льду идти. Тожеretainне дергает, но иnilтебе никто не подставит. Думаешь, объект жив? А он уже на дне. И ты, довольный, шагаешь — и проваливаешься в краш, блядь. Ответственность — твоя, собака сука.- Циклы сильных ссылок: Вот это, блядь, классика! Два объекта держат друг друга за жопу сильными ссылками. ARC смотрит на это, чешет репу и говорит: «Ну, ёпта, оба живы, нихуя не сделаешь». А они на самом деле уже мертвы для всего мира, но память жрут. Спасение — только
weakилиunowned, чтобы разорвать этот ебаный круг.