Ответ
Swift использует автоматический подсчет ссылок (ARC) и предоставляет три типа ссылок для управления владением объектами и предотвращения циклов сильных ссылок (strong reference cycles):
| Тип ссылки | Влияние на счетчик ссылок (retain count) | Описание | Объявление |
|---|---|---|---|
strong (сильная) |
Увеличивает на 1. | Ссылка по умолчанию. Объект удерживается в памяти, пока существует хотя бы одна сильная ссылка на него. | var object: SomeClass |
weak (слабая) |
Не увеличивает. | Не удерживает объект. Автоматически становится nil, когда объект освобождается. Всегда должна быть optional (var). |
weak var delegate: SomeDelegate? |
unowned (бесхозная) |
Не увеличивает. | Предполагает, что объект будет существовать на протяжении всей жизни ссылки. Не является optional. При обращении к освобожденному объекту вызывает краш (runtime error). | unowned let parent: ViewController |
Когда использовать?
-
strong: Для обычных отношений «владелец-объект». Большинство ссылок в коде являются сильными. -
weak: Для ссылок, которые могут бытьnil(опциональные связи), особенно в случаях обратных ссылок, чтобы разорвать цикл.-
Типичный пример: Делегат (Delegate).
protocol MenuDelegate: AnyObject { /* ... */ } class MenuViewController { weak var delegate: MenuDelegate? // Слабая ссылка! } class MainViewController: MenuDelegate { let menu = MenuViewController() init() { menu.delegate = self // MainViewController не удерживается menu } } - Также используется для
IBOutlet(связей из Storyboard), если они не являются корневыми view.
-
-
unowned: Используется, когда время жизни ссылающегося объекта короче или равно времени жизни объекта, на который ссылаются. Гарантия существования лежит на архитектуре приложения.-
Типичный пример: Замыкание (closure), захватывающее
self, когдаselfгарантированно не станетnilраньше вызова замыкания.class NetworkManager { var onComplete: (() -> Void)? func fetchData(completion: @escaping () -> Void) { self.onComplete = completion // ... асинхронная операция } func handleResponse() { onComplete?() // Замыкание будет вызвано } } class DataHandler { let manager = NetworkManager() private var data: String = "" func load() { // Используем unowned, т.к. DataHandler живет дольше, чем операция fetchData, // и не будет деинициализирован до вызова замыкания. manager.fetchData { [unowned self] in self.data = "Loaded" // Краш, если self был освобожден! } } } - Более безопасная альтернатива
unowned–weakс optional binding.manager.fetchData { [weak self] in guard let self = self else { return } self.data = "Loaded" // Безопасно }
-
Ключевое правило: Используйте weak для опциональных обратных ссылок (делегаты, замыкания) и unowned только когда абсолютно уверены в времени жизни объектов. В сомнительных случаях предпочитайте weak.