swift - custom - uiviewcontroller




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

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

Этот код дает ошибку компиляции ( weak не может применяться к типу MyClassDelegate к классу):

class MyClass {
  weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate {
}

Мне нужно префикс протокола с помощью @objc , тогда он работает.

Вопрос: Что такое «чистый» быстрый способ добиться weak delegate ?


Дополнительный ответ

Меня всегда смущало то, должны ли делегаты быть слабыми или нет. Недавно я узнал больше о делегатах и ​​когда использовал слабые ссылки, поэтому позвольте мне добавить некоторые дополнительные пункты здесь для будущих зрителей.

  • Цель использования weak ключевого слова - избежать сильных эталонных циклов (удерживать циклы). Сильные циклы ссылок происходят, когда два экземпляра класса имеют сильные ссылки друг на друга. Их подсчеты ссылок никогда не обращаются к нулю, поэтому они никогда не освобождаются.

  • Вам нужно использовать только weak если делегат является классом. Строки Swift и перечисления представляют собой типы значений (их значения копируются при создании нового экземпляра), а не ссылочные типы, поэтому они не создают сильных ссылочных циклов.

  • weak ссылки всегда являются необязательными (в противном случае вы использовали бы unowned ) и всегда используете var (not let ), чтобы опционально можно было установить значение nil когда оно освобождено.

  • Родительский класс должен, естественно, иметь сильную ссылку на свои дочерние классы и, следовательно, не использовать ключевое слово weak . Однако, когда ребенок хочет ссылку на своего родителя, он должен сделать его слабым, используя weak ключевое слово.

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

  • Как правило, делегаты должны быть помечены как weak потому что большинство делегатов ссылаются на классы, которыми они не владеют. Это определенно верно, когда ребенок использует делегат для связи с родителем. Тем не менее, есть еще некоторые ситуации, когда делегат может и должен использовать сильную ссылку.

  • Протоколы могут использоваться как для ссылочных типов (классов), так и для типов значений (structs, enums). Поэтому в случае, когда вам нужно сделать делегат слабым, вам нужно добавить ключевое слово class к протоколу, чтобы он знал, что он должен использоваться только с ссылочными типами.

    protocol MyClassDelegate: class {
        // ...
    }
    
    class SomeClass {
        weak var delegate: MyClassDelegate?
    }
    

Дальнейшее обучение

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

связанные с


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

public protocol UIScrollViewDelegate : NSObjectProtocol {
   ...
}

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


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

class MyClass {
    weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate: AnyObject {
}

От Apple:

Чтобы предотвратить сильные ссылочные циклы, делегаты должны быть объявлены как слабые ссылки. Дополнительные сведения о слабых ссылках см. В разделе Сильные ссылочные циклы между экземплярами классов. Маркировка протокола как класса позволит позже объявить, что делегат должен использовать слабую ссылку. Вы отмечаете, что протокол является классом только путем наследования из AnyObject , как описано в протоколах только для классов.

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. Он гарантирует, что ваш протокол применяется к классу, а не к перечислению или структуре. См. «Проверка соответствия протокола» в руководстве.





swift-protocols