Как я могу сделать слабую ссылку на протокол в "чистом" Swift (без @objc)
weak
ссылки не работают в системе SWIFT, если protocol
объявлен @objc
, который я не хочу в чистом быстром приложении.
этот код дает ошибку при компиляции (weak
не может быть применено к неклассового типа MyClassDelegate
):
class MyClass {
weak var delegate: MyClassDelegate?
}
protocol MyClassDelegate {
}
мне нужно, чтобы префикс протокола @objc
, то он работает.
вопрос: каков "чистый" быстрый способ выполнить weak
delegate
?
5 ответов:
вам нужно объявить тип протокола как
class
.protocol ProtocolNameDelegate: class { // Protocol stuff goes here } class SomeClass { weak var delegate: ProtocolNameDelegate? }
Я так понимаю, что с помощью
class
, вы гарантируете, что этот протокол будет использоваться только для классов и никаких других вещей, таких как перечисления или структуры.
Дополнительный Ответ
меня всегда смущало, должны ли делегаты быть слабыми или нет. Недавно я узнал больше о делегатах и когда использовать слабые ссылки, поэтому позвольте мне добавить некоторые дополнительные моменты здесь ради будущих зрителей.
цель использования
weak
ключевое слово, чтобы избежать сильных опорных циклов (сохранить циклы). Сильные ссылочные циклы происходят, когда два экземпляра класса имеют сильные ссылки друг на друга. Их количество ссылок никогда не доходит до нуля, поэтому они никогда не освобождаются.вам нужно использовать
weak
если делегат является классом. Swift структуры и перечисления являются типами значений (их значения копируются при создании нового экземпляра), а не ссылочными типами, поэтому они не делают strong ссылка циклы.
weak
ссылки всегда являются необязательными (в противном случае вы бы использовалиunowned
) и всегда использоватьvar
(неlet
) так что необязательный может быть установлен вnil
, когда он освобождается.родительский класс, естественно, должен иметь сильную ссылку на свои дочерние классы и, следовательно, не использовать
weak
ключевое слово. Когда ребенок хочет ссылку на своего родителя, хотя, он должен сделать его слабой ссылкой с помощьюweak
ключевое слово.
weak
должен использоваться, когда вы хотите ссылку на класс, который вам не принадлежит, а не только для дочернего элемента, ссылающегося на своего родителя. Когда два неиерархических класса должны ссылаться друг на друга, выберите один, чтобы быть слабым. Тот, который вы выберете, зависит от ситуации. Смотрите ответы на этот вопрос подробнее об этом.как правило, делегаты должны быть помечены как
weak
потому что большинство делегатов ссылаются на классы, что им не принадлежит. Это определенно верно, когда ребенок использует делегат для связи с родителем. Тем не менее, есть еще в некоторых случаях где делегат может и должен использовать сильную ссылку.протоколы могут быть использованы как для ссылка типа (классов) и типы значений (структуры, перечисления). Поэтому в вероятном случае, когда вам нужно сделать делегат слабым, вы должны добавить
class
ключевое слово для протокола, чтобы он знал, что он должен использоваться только со ссылочными типами.protocol MyClassDelegate: class { // ... } class SomeClass { weak var delegate: MyClassDelegate? }
далее Исследование
чтение следующих статей-это то, что помогло мне понять это намного лучше. Они также обсуждают связанные с этим вопросы, такие как
unowned
ключевое слово и сильные опорные циклы, которые происходят с закрытиями.
- Swift документация:Автоматический Подсчет Ссылок
- "Слабый, Сильный, Никому Не Принадлежащий, О Боже!"- Руководство по ссылкам в Swift
- сильные, слабые и никому не принадлежащие-сортировка дуги и Свифт
по теме
AnyObject
это официальный способ использовать слабую ссылку в Swift.class MyClass { weak var delegate: MyClassDelegate? } protocol MyClassDelegate: AnyObject { }
От Apple:
чтобы предотвратить сильные ссылочные циклы, делегаты должны быть объявлены как слабая ссылка. Дополнительные сведения о слабых ссылках см. В разделе Сильные Ссылочные Циклы Между Экземплярами Класса. Маркировка протокола as class-only позже позволит вам объявить, что делегат должен использовать слабую ссылку. Вы отмечаете протокол как класс-только наследование от какой-либо объект, как описано в протоколах только для класса.
обновление: Похоже, что руководство было обновлено, и пример, на который я ссылался, был удален. См. редактирование ответа @flainez выше.
Оригинал: Использование @objc-это правильный способ сделать это, даже если вы не взаимодействуете с Obj-C. Это гарантирует, что ваш протокол применяется к классу, а не к перечислению или структуре. См. "проверка на соответствие протоколу" в руководстве.