Ответ
Сильная ссылка (strong reference) — это ссылка по умолчанию в Swift, которая увеличивает счетчик ссылок (retain count) объекта в куче. Пока существует хотя бы одна сильная ссылка, объект не будет освобожден.
Пример множественных сильных ссылок:
class Person {
let name: String
init(name: String) { self.name = name; print("(name) инициализирован") }
deinit { print("(name) деинициализирован") }
}
var reference1: Person? = Person(name: "Alice") // Retain count = 1
var reference2: Person? = reference1 // Retain count = 2
var reference3: Person? = reference1 // Retain count = 3
reference1 = nil // Retain count = 2
reference2 = nil // Retain count = 1
reference3 = nil // Retain count = 0 -> Срабатывает deinit
Критическая проблема: Циклы сильных ссылок (Strong Reference Cycle) Возникает, когда два объекта ссылаются друг на друга через сильные ссылки, создавая изолированный граф, который никогда не будет освобожден.
class Person {
let name: String
var apartment: Apartment? // Сильная ссылка на Apartment
init(name: String) { self.name = name }
deinit { print("(name) освобожден") }
}
class Apartment {
let unit: String
var tenant: Person? // Сильная ссылка на Person
init(unit: String) { self.unit = unit }
deinit { print("Апартаменты (unit) освобождены") }
}
var john: Person? = Person(name: "John")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john // ЦИКЛ: Person → Apartment → Person
john = nil // Объект Person НЕ освобождается (retain count = 1)
unit4A = nil // Объект Apartment НЕ освобождается (retain count = 1)
// ПАМЯТЬ УТЕКАЕТ
Решение: Слабые (weak) и бесхозные (unowned) ссылки
-
weak— не увеличивает retain count. Становитсяnil, когда объект освобождается.class Apartment { weak var tenant: Person? // Решение: слабая ссылка } -
unowned— какweak, но предполагает, что объект существует всегда. При обращении к освобожденному объекту — краш.class Customer { let card: CreditCard init(card: CreditCard) { self.card = card } } class CreditCard { unowned let customer: Customer // Customer всегда существует дольше init(customer: Customer) { self.customer = customer } }
Правило: Используйте weak для опциональных ссылок, которые могут стать nil. Используйте unowned для ссылок, которые всегда имеют значение в течение жизни объекта.
Ответ 18+ 🔞
А, ну вот, классика жанра, блядь! Сильные ссылки в Swift — это как тот самый Герасим, который за всё хватается и не отпускает, пока в рот ему чих-пых!
Смотри, есть у тебя объект в памяти, в этой куче, блядь. Сильная ссылка — это как будто ты взял его за жопу и кричишь: «Моё!». Пока хоть один такой придурок держит, объект живой. Счётчик этих держателей (retain count) увеличивается.
class Person {
let name: String
init(name: String) { self.name = name; print("(name) инициализирован") }
deinit { print("(name) деинициализирован") }
}
var reference1: Person? = Person(name: "Alice") // Держу я! (count = 1)
var reference2: Person? = reference1 // И я держу! (count = 2)
var reference3: Person? = reference1 // О, и я с вами! (count = 3)
reference1 = nil // Я отпустил (count = 2)
reference2 = nil // И я отпустил (count = 1)
reference3 = nil // Все отпустили, ёпта! (count = 0) -> *бабах* deinit!
Всё вроде логично, да? Ан нет! Сейчас начнётся самое интересное, блядь — Циклы сильных ссылок. Это когда два упыря схватили друг друга в охапку и не хотят отпускать. Мёртвая хватка, ёпта!
class Person {
let name: String
var apartment: Apartment? // Сильно хватаю квартиру
init(name: String) { self.name = name }
deinit { print("(name) освобожден") }
}
class Apartment {
let unit: String
var tenant: Person? // Сильно хватаю жильца
init(unit: String) { self.unit = unit }
deinit { print("Апартаменты (unit) освобождены") }
}
var john: Person? = Person(name: "John")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A // Джон хватает квартиру.
unit4A!.tenant = john // Квартира хватает Джона. ПИЗДЕЦ, ЦИКЛ!
john = nil // Ты думаешь, Джон освободился? Хуй там! Квартира же его держит!
unit4A = nil // А квартира? А её Джон держит! Замкнутый круг, блядь!
// Оба объекта теперь болтаются в памяти, как призраки. УТЕЧКА! Совесть, как у Герасима, должна заглодать, но компилятор-то молчит!
Вот такая ебля получается. Два мудака друг за друга держатся, и оба сдохнуть не могут. Память течёт, как вода из дырявого ведра.
Спасение, блядь! Есть два выхода, как разжать эти ебучкие хватки.
-
weak— слабая ссылка. Это как сказать: «Я тебя держу, но если ты сдохнешь — я тебя отпущу и даже не заплачу». Ссылка становитсяnil, когда объект освобождается. Для опциональных типов — самое то.class Apartment { weak var tenant: Person? // Я не настаиваю, живи как знаешь. } // Теперь, когда Джона (john) прибьют (nil), квартира (unit4A) просто скажет: "Ну и хуй с ним, tenant = nil". -
unowned— бесхозная ссылка. Это похуистичнее. Ты говоришь: «Этот объект будет жить ВСЕГДА, пока я жив. Я на него ссылаюсь, но не держу». А если он всё-таки сдохнет раньше тебя, и ты к нему обратишься — БАБАХ! Краш приложения, в рот меня чих-пых! Используй, только если на 100500% уверен в порядке жизни объектов.class Customer { let card: CreditCard init(card: CreditCard) { self.card = card } } class CreditCard { unowned let customer: Customer // Карта не может жить без владельца. Владелец всегда умрёт позже. init(customer: Customer) { self.customer = customer } } // Если Customer удалить, а CreditCard попытается достучаться до customer — будет тебе пиздец, runtime error.
Короче, правило простое, блядь:
weak— когда ссылка может статьnil(опциональная хуйня).unowned— когда ссылка НИКОГДА не станетnilв течение всей жизни ссылающегося объекта (но это надо проверять, а то охуеешь потом).
Вот и вся магия, ёпта. Не создавай циклы, а то память утечёт, и будешь как тот самый Герасим — с пустыми руками и совестью, которая жрёт изнутри.