Как я могу сделать слабую ссылку на протокол в "чистом" Swift (без @objc)

weak ссылки, похоже, не работают в Swift, если только protocol объявлен @objc, который я не хочу в чистом приложении Swift.

этот код дает ошибку при компиляции (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?
    }
    

далее Учись!--15-->

чтение следующих статей-это то, что помогло мне понять это намного лучше. Они также обсуждают связанные с этим вопросы, такие как unowned ключевое слово и сильные опорные циклы, которые происходят с закрытиями.

по теме


AnyObject является официальным способом использования слабой ссылки в Swift.

class MyClass {
    weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate: AnyObject {
}

От Apple:

чтобы предотвратить сильные опорные циклы, делегаты должны быть объявлены как слабая ссылка. Дополнительные сведения о слабых ссылках см. В разделе Сильные Опорные Циклы Между Экземплярами Класса. Маркировка протокола as class-only позже позволит вам объявить, что делегат должен использовать слабую ссылку. Вы отмечаете протокол как класс-только наследование от какой-либо объект, как обсуждалось в протоколах только класса.

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276


обновление: Похоже, что руководство было обновлено, и пример, на который я ссылался, был удален. См. редактирование ответа @flainez выше.

Оригинал: Использование @objc-правильный способ сделать это, даже если вы не взаимодействуете с Obj-C. Это гарантирует, что ваш протокол применяется к классу, а не к перечислению или структуре. См." проверка соответствия протоколу " в руководстве.


Apple использует "NSObjectProtocol" вместо "class".

public protocol UIScrollViewDelegate : NSObjectProtocol {
   ...
}

Это также работает для меня и удаляет ошибки, которые я видел при попытке реализовать свой собственный шаблон делегата.