На объект оставили только слабую ссылку. Какое значение напечатает код после выхода из области видимости и почему?
final class Token {}
final class Store {
weak var token: Token?
}
let store = Store()
do {
let token = Token()
store.token = token
print(store.token != nil)
}
print(store.token == nil)
Код напечатает true, затем true. Свойство weak не удерживает экземпляр Token от удаления: после выхода переменной token из области видимости сильных ссылок на объект не остаётся, поэтому ARC освобождает объект, а слабая ссылка автоматически становится nil.
В Swift управление временем жизни объектов выполняет ARC — подсчёт ссылок. Сильные ссылки увеличивают счётчик владения, а объект освобождается, когда сильных ссылок больше нет.
Одних сильных ссылок недостаточно: взаимные ссылки объектов могут образовать цикл, при котором оба объекта никогда не освобождаются. Слабые ссылки появились как способ наблюдать за объектом или связывать объекты без добавления владения.
Store должен ссылаться на Token, но не должен продлевать его жизнь. Если вместо weak использовать обычное свойство, store сохранит сильную ссылку на токен, и объект останется в памяти после выхода из блока.
Слабая ссылка всегда имеет Optional-тип, потому что объект может быть освобождён в любой момент после исчезновения последней сильной ссылки. Поэтому обращение к store.token требует учитывать возможное значение nil.
Внутри блока объект Token удерживается сильной локальной переменной token. Присваивание store.token = token устанавливает только слабую ссылку и не добавляет ещё одного владельца, поэтому первый print получает ненулевое значение.
После выхода из блока локальная сильная ссылка уничтожается. Store всё ещё существует, но его свойство token не владеет объектом. ARC освобождает Token, а runtime автоматически обнуляет слабую ссылку; второй print проверяет именно это состояние.
Минимальный вариант с явным чтением Optional:
weak применим только к ссылкам на экземпляры классов или class-bound протоколов. Он подходит для не владеющих связей, например делегата, наблюдателя или обратной ссылки в графе объектов.
Альтернатива — unowned. Она также не удерживает объект, но не становится Optional и не проверяет доступность объекта. Если объект уже освобождён, обращение через unowned приводит к аварийному завершению, поэтому этот вариант допустим только при гарантированно совместном времени жизни объектов.
Контроллер экрана хранит делегат сервиса. Сервис при этом уже владеет контроллером через callback. Сильные ссылки с обеих сторон создадут цикл: закрытие экрана не освободит контроллер и связанные ресурсы.
Использование обычной сильной ссылки проще, но может привести к утечке памяти. unowned не создаёт цикл и не требует Optional, однако опасен, если сервис переживёт контроллер. weak безопаснее: после уничтожения контроллера ссылка сервиса станет nil, но код обязан обработать отсутствие делегата.
Для делегата обычно выбирают weak, потому что его время жизни не должно зависеть от владельца сервиса. В результате экран освобождается после закрытия, а сервис не вызывает уже уничтоженный объект.
Почему weak-свойство обязательно Optional?
Слабая ссылка не управляет временем жизни объекта. Последняя сильная ссылка может исчезнуть независимо от владельца слабой ссылки, поэтому прежнее значение может перестать существовать. Runtime обнуляет такую ссылку, и тип Optional отражает возможность этого состояния.
Чем weak отличается от unowned по последствиям чтения?
weak хранит ссылку, которая автоматически становится nil, поэтому чтение безопасно, но требует Optional-обработки. unowned предполагает, что объект всё ещё существует; после его освобождения чтение недействительной ссылки вызывает runtime-ошибку. unowned может быть уместен при доказуемо более короткой или равной жизни владельца, weak — когда объект может исчезнуть независимо.
Создаёт ли копирование структуры со свойством weak независимую ссылку?
Нет. Структура копируется по значению, но её weak-свойство после копирования указывает на тот же экземпляр объекта. Обе копии не владеют объектом, поэтому освобождение последней сильной ссылки обнулит слабые ссылки в обеих копиях; независимость значения структуры не означает независимость ссылочного объекта.