Как и где хранятся weak (слабые) ссылки в Swift?

Ответ

weak ссылки хранятся в отдельной таблице слабых ссылок (weak table или side table), которая поддерживается runtime. Эта таблица ассоциирована с объектом.

Принцип работы:

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

Пример:

class MyClass {}
var strongRef: MyClass? = MyClass() // Создан объект
weak var weakRef = strongRef        // weak-ссылка зарегистрирована в таблице
print(weakRef) // Optional(MyClass)
strongRef = nil                     // Объект деаллоцируется
// Runtime обнуляет weakRef через таблицу
print(weakRef) // nil

Зачем это нужно:

  • weak ссылки не увеличивают счетчик ссылок, что помогает избежать циклов сильных ссылок (retain cycles).
  • Автоматическое обнуление делает использование безопасным.
  • Типичное применение: делегаты, замыкания с [weak self].

Ответ 18+ 🔞

А, ну это ж классика, блядь! Слабые ссылки, ёпта! Это как твой друг, который обещал помочь с переездом, а в день Х взял и свалил на хуй, и телефон не берёт. Только тут система сама за тебя всё делает, не то что эти ненадёжные уёбки.

Смотри, есть у тебя объект, да? И ты на него можешь смотреть по-разному. Можно сильно — это как вцепиться в него и не отпускать, пока сам не помрёшь. А можно слабо — это как посмотреть на него издалека, через бинокль, и сказать: «О, прикольно, объект есть!». А если его кто-то другой (сильная ссылка) отпустит, и он сдохнет, то твой бинокль просто покажет пустоту, хуй с горы, а не сломается.

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

Как это, блядь, работает:

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

Пример, чтобы совсем пиздец стало понятно:

class MyClass {} // Просто какой-то класс, неважно какой
var strongRef: MyClass? = MyClass() // Сильная хватка! Создали и держим.
weak var weakRef = strongRef        // А это слабый взгляд. Записались в книжку наблюдателей.
print(weakRef) // Optional(MyClass) — Опа, вижу его! Живой!

strongRef = nil                     // Сильная хватка разжалась. Объект полетел в тартарары.
// Runtime в этот момент листает книжку, находит weakRef и пишет ему: "Чувак, всё, него нет. Держи nil."
print(weakRef) // nil — Ёпта, а где он? А нету. Пустота.

И зачем этот цирк, спросишь ты? А затем, блядь, чтобы не попасть в цикл сильных ссылок! Это когда два объекта держат друг друга так сильно, что ни один не может умереть, и память течёт, как говно по трубам. weak ссылка — это как договор: «Я на тебя посмотрю, но если ты сдохнешь — я не буду из-за этого убиваться, я просто забуду тебя». Идеально для делегатов или для [weak self] в замыканиях, чтобы само замыкание не держало твой контроллер вечно в памяти, как маньяк-рецидивист.