Можно ли объявить слабую ссылку (weak) на переменную типа протокол?

«Можно ли объявить слабую ссылку (weak) на переменную типа протокол?» — вопрос из категории Управление памятью, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, но только если протокол ограничен ссылочными типами. Для этого протокол должен быть помечен как AnyObject (или устаревший class).

Корректный пример:

// Протокол, который могут реализовывать только классы
protocol MyDelegate: AnyObject {
    func didCompleteTask()
}

class MyClass {
    // Слабая ссылка разрешена, так как протокол AnyObject
    weak var delegate: MyDelegate?
}

Почему это важно:

  • weak предотвращает циклы сильных ссылок (retain cycles) между объектами.
  • Когда объект-делегат удаляется из памяти, weak-ссылка автоматически становится nil.

Ошибка компиляции: Если протокол не ограничен AnyObject, компилятор выдаст ошибку:

protocol DataSource { // Не помечен как AnyObject
    func fetchData()
}

class Manager {
    weak var source: DataSource? // Ошибка: 'weak' cannot be applied to non-class type 'DataSource'
}

Ключевое правило: weak и unowned работают только с ссылочными типами (классами). Поскольку протоколы по умолчанию могут быть приняты и структурами, и перечислениями, необходимо явно ограничить их только классами с помощью AnyObject.