weak
ссылки не работают в Swift, если только protocol
не объявлено как @objc
, чего я не хочу в чистом приложении Swift.
Этот код выдает ошибку компиляции ( weak
не может быть применен к не классу MyClassDelegate
):
class MyClass {
weak var delegate: MyClassDelegate?
}
protocol MyClassDelegate {
}
Мне нужно префикс протокола с @objc
, тогда он работает.
Вопрос: Что такое «чистый» способ Свифта weak
delegate
?
Ответы:
Вам необходимо объявить тип протокола как
AnyObject
.Используя это,
AnyObject
вы говорите, что только классы могут соответствовать этому протоколу, тогда как структуры или перечисления не могут.источник
protocol ProtocolNameDelegate: AnyObject
, но это не имеет значения.AnyObject
потомуclass
что в какой-то момент будет устаревшим.Дополнительный ответ
Меня всегда смущало, должны ли делегаты быть слабыми или нет. Недавно я узнал больше о делегатах и о том, когда использовать слабые ссылки, поэтому позвольте мне добавить некоторые дополнительные замечания здесь для будущих зрителей.
Цель использования
weak
ключевого слова - избежать циклов сильных ссылок (сохранить циклы). Сильные ссылочные циклы происходят, когда два экземпляра класса имеют сильные ссылки друг на друга. Их счетчик ссылок никогда не обнуляется, поэтому их никогда не освобождают.Вам нужно использовать только
weak
если делегат является классом. Структуры и перечисления Swift являются типами значений (их значения копируются при создании нового экземпляра), а не ссылочными типами, поэтому они не создают сильных ссылочных циклов.weak
ссылки всегда являются необязательными (в противном случае вы бы их использовалиunowned
) и всегда используетеvar
(неlet
), так что необязательный может быть установлен,nil
когда он освобожден.Естественно, родительский класс должен иметь строгую ссылку на свои дочерние классы и поэтому не должен использовать
weak
ключевое слово. Когда ребенок хочет ссылку на своего родителя, он должен сделать его слабой ссылкой, используяweak
ключевое слово.weak
должен использоваться, когда вы хотите ссылку на класс, который вам не принадлежит, а не только на ребенка, ссылающегося на его родителя. Когда два неиерархических класса должны ссылаться друг на друга, выберите один, чтобы быть слабым. Выбор зависит от ситуации. Смотрите ответы на этот вопрос для получения дополнительной информации по этому вопросу.Как правило, делегаты должны быть помечены так,
weak
потому что большинство делегатов ссылаются на классы, которыми они не владеют. Это определенно верно, когда ребенок использует делегата для общения с родителем. Использование слабой ссылки для делегата - это то, что рекомендует документация . (Но посмотрите и это тоже.)Протоколы могут использоваться как для ссылочных типов (классов), так и для типов значений (структуры, перечисления). Таким образом, в вероятном случае, когда вам нужно сделать делегата слабым, вы должны сделать его протоколом только для объекта. Способ сделать это - добавить
AnyObject
в список наследования протокола. (В прошлом вы делали это с помощьюclass
ключевого слова, ноAnyObject
сейчас это предпочтение .)Дальнейшее изучение
Чтение следующих статей помогло мне понять это намного лучше. Они также обсуждают связанные вопросы, такие как
unowned
ключевое слово и циклы сильных ссылок, которые происходят с замыканиями.связанные с
источник
AnyObject
это официальный способ использовать слабую ссылку в Swift.От Apple:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276
источник
class
рекомендуется в Swift 4.1?Обновление: похоже, руководство было обновлено, а пример, на который я ссылался, был удален. Смотрите изменение ответа @ flainez выше.
Оригинал: использование @objc - верный способ сделать это, даже если вы не взаимодействуете с Obj-C. Это гарантирует, что ваш протокол применяется к классу, а не к перечислению или структуре. См. «Проверка соответствия протокола» в руководстве.
источник
протокол должен быть подклассом AnyObject, класса
пример приведен ниже
источник
Apple использует «NSObjectProtocol» вместо «class».
Это также работает для меня и устраняет ошибки, которые я видел при попытке реализовать свой собственный шаблон делегата.
источник