Что такое weak и unowned? Чем они отличаются?ios-40

Общее назначение

Оба модификатора используются для разрыва сильных ссылочных циклов (retain cycles), но делают это по-разному.

Weak

Характеристики:

  • Автоматически становится nil при освобождении объекта
  • Всегда объявляется как var (так как может измениться на nil)
  • Опциональный тип (требует раскрытия через ? или !)
  • Безопасна - нет риска обращения к освобожденной памяти

Пример использования:

class Person {
    weak var apartment: Apartment?
    // ...
}

Когда использовать:

  1. Когда ссылка может стать nil в течение жизни объекта
  2. Для делегатов (обычно weak)
  3. В обратных ссылках в parent-child отношениях

Unowned

Характеристики:

  • Не становится nil (неопциональный тип)
  • Приводит к крашу при обращении к освобожденному объекту
  • Немного быстрее weak (не требует управления nil)
  • Аналогична implicit unwrapped optional по поведению

Пример использования:

class Customer {
    unowned let creditCard: CreditCard
    // ...
}

Когда использовать:

  1. Когда ссылка никогда не станет nil в течение жизни объекта
  2. В отношениях где вложенный объект не может существовать без родителя
  3. Для оптимизации производительности в критических местах

Сравнительная таблица

Критерийweakunowned
Опциональность Да (Optional) Нет
Безопасность Высокая (nil-safe) Низкая (может крашнуться)
Производительность Медленнее Быстрее
Использование var let/var
Когда использовать Когда объект может стать nil Когда объект гарантированно существует

Практические примеры

1. Делегаты

protocol DataLoaderDelegate: AnyObject {
    func didLoad(data: Data)
}

class DataLoader {
    weak var delegate: DataLoaderDelegate?
}

2. Parent-child отношения

class Parent {
    var child: Child?
}

class Child {
    unowned let parent: Parent
    init(parent: Parent) { self.parent = parent }
}

3. Замыкания

dataLoader.loadData { [weak self] data in
    guard let self = self else { return }
    self.handle(data)
}

// Или для гарантированно существующего self:
dataLoader.loadData { [unowned self] data in
    self.handle(data) // Рискованно!
}

Частые ошибки

  1. Использование unowned когда объект может стать nil

    // Опасный код!
    unowned var delegate: DataLoaderDelegate?
    
  2. Циклы в замыканиях без weak/unowned

    class MyClass {
        var closure: (() -> Void)?
    
        func setup() {
            closure = { self.doSomething() } // Retain cycle!
        }
    }
    
  3. Чрезмерное использование unowned "для производительности"

Рекомендации

  1. По умолчанию используйте weak - это безопаснее
  2. Unowned только когда уверены на 100% в времени жизни объекта
  3. В замыканиях предпочитайте [weak self] с guard
  4. Для протоколов делегатов добавляйте : AnyObject

Резюмируем

  • weak - безопасная опциональная ссылка, обнуляется автоматически
  • unowned - небезопасная неопциональная ссылка, требует уверенности в существовании объекта
  • Выбор зависит от гарантий времени жизни объектов
  • Лучшая практика: начинать с weak, переходить на unowned только при необходимости и полной уверенности

Правильное использование этих модификаторов предотвращает утечки памяти и делает код стабильнее.