Какие ограничения накладывает weak-ссылка в Swift?

Ответ

Weak-ссылка (weak) не создаёт сильного (strong) владения объектом, что помогает избежать циклов сильных ссылок. Её ключевые ограничения:

  • Всегда Optional: Поскольку weak-ссылка автоматически становится nil при освобождении объекта, она должна быть объявлена как опциональная (weak var delegate: SomeDelegate?).
  • Только для ссылочных типов: Weak работает исключительно с экземплярами классов (reference types). Для структур и перечислений (value types) она неприменима.
  • Отсутствие атомарности доступа: Чтение и запись weak-переменной не являются атомарными операциями. В многопоточной среде объект может быть освобождён между проверкой на nil и его использованием.
  • Не гарантирует немедленное обнуление: ARC может обнулить weak-ссылку не мгновенно, а в следующий run loop цикл.

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

class ViewController {
    weak var delegate: DataProviderDelegate? // Weak, чтобы не удерживать делегата
}

class DataProvider {
    var controller: ViewController? // Сильная ссылка
}
// При уничтожении DataProvider, ViewController может быть освобождён,
// так как delegate на него не держит сильную ссылку.

Ответ 18+ 🔞

А, слушай, про weak-ссылки, это ж классика, блядь! Ну, типа, чтобы не попасть в просак с этими ебучими циклами удержания, когда два объекта друг за друга цепляются, как два алкаша у подъезда — и оба нахуй не могут разойтись, память жрут!

Смотри, суть проще пареной репы: weak — это как сказать «я тебя знаю, но за тебя не отвечаю, нахер». Сильной хватки нет. И отсюда, блядь, вытекают все её приколы, прям как из пьяного деда:

  1. Она всегда Optional, ёпта. Ну логично же! Объект, на который ты слабо ссылаешься, может в любой момент, как последняя надежда, — испариться. И ссылка автоматом станет nil. Поэтому объявлять надо так: weak var какой-тоМудак: SomeClass?. Не можешь ты weak сделать не-опшинал, это как пытаться удержать воду в решете — нихуя не выйдет.

  2. Только для классов, блядь! На структуры и енумы даже не смотри — они ж не ссылочные, они по значению живут. Weak — это исключительно для этих зажравшихся ссылочных типов, которые в куче сидят.

  3. Атомарности — ноль ебать. Вот это важный момент, многие проёбываются. Читаешь weak-переменную, проверяешь, что она не nil, и тут — бац! — в другом потоке объект приказал долго жить. И ты пытаешься к уже освобождённой памяти обратиться. Пиздец, креш. Между проверкой и использованием всё может ебануться.

  4. Мгновенного обнуления не жди. ARC — он не мгновенная справедливость, блядь. Он может weak-ссылку обнулить не прям щас, а в следующем цикле ранлупа. Так что не удивляйся, если объект уже вроде как должен был сдохнуть, а weak-ссылка ещё какое-то время не nil. Жизнь, сука, сложная штука.

Ну и главный кейс, ради которого это всё и затеяно — разорвать ебучую петлю. Смотри, как красота:

class ViewController {
    weak var delegate: DataProviderDelegate? // Слабая ссылка. Я делегата вижу, но не душу.
}

class DataProvider {
    var controller: ViewController? // А вот это уже сильная хватка, да.
}

Вот и вся магия. DataProvider держит ViewController за горло сильной ссылкой. А ViewController на делегата (DataProvider) только пальчиком слабым показывает: «Вон он». Когда DataProvider решает наложить на себя руки (деинициализироваться), ViewController не держит его сильной ссылкой — weak-то! — и оба спокойно идут на свалку памяти, не заставляя друг друга страдать. Красота, блядь, ебать мои старые костыли!

Вот так-то, а то некоторые думают, что weak — это просто модное слово. Ан нет, хитрая жопа, которая от больших проблем спасает.