Не метод@взаимодействию их не удовлетворяют факультативное требование протокола@взаимодействию'


описание:

  • у меня есть протокол P1, который обеспечивает реализацию по умолчанию одной из дополнительных функций Objective-C.
  • когда я предоставляю реализацию по умолчанию необязательной функции, появляется предупреждение

Предупреждение Компилятора:

Non-'@objc' method 'presentationController(_:viewControllerForAdaptivePresentationStyle:)' does not satisfy optional requirement of '@objc' protocol 'UIAdaptivePresentationControllerDelegate'

версия:

  • Swift: 3
  • Xcode: 8 (public release)

попытки:

  • пробовал добавлять @objc но не помогает

вопрос:

  • как мне решить эту проблему ?
  • есть ли обойти ?

код:

@objc protocol P1 : UIAdaptivePresentationControllerDelegate {

}

extension P1 where Self : UIViewController {

    func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
        return UIViewController()
    }
}


class A : UIViewController, P1 {

}
1 65

1 ответ:

хотя я думаю, что я могу ответить на ваш вопрос, это не ответ вам понравится.

TL; DR:@objc функции в настоящее время не может быть в расширениях протокола. Вместо этого вы можете создать базовый класс, хотя это не идеальное решение.

расширения протокола и Objective-C

во-первых, этот вопрос/ответ (может ли Swift метод, определенный на расширениях по протоколам, доступным в Objective-c) кажется, это потому, что из того, как расширения протокола отправляются под капотом, методы, объявленные в расширениях протокола, не видны objc_msgSend() функции, и поэтому не видны для Objective-C кода. Поскольку метод, который вы пытаетесь определить в своем расширении, должен быть виден Objective-C (so UIKit может использовать его), он кричит на вас за то, что вы не включили @objc, но как только вы включаете его, он кричит на вас, потому что @objc Не допускается в расширениях протокола. Это наверное потому, что протокол расширения в настоящее время не могут быть видны Objective-C.

мы также можем видеть, что сообщение об ошибке после добавления @objc состояния " @objc можно использовать только с членами классов, протоколами @objc и конкретными расширениями классов."Это не класс; расширение протокола @objc не то же самое, что в самом определении протокола (т. е. в требованиях), и слово "конкретный" предполагает, что расширение протокола не считается конкретным классом расширение.

решение

к сожалению, это в значительной степени полностью предотвращает использование расширений протокола, когда реализации по умолчанию должны быть видны в рамках Objective-C. Сначала я подумал, что, возможно,@objc не было разрешено в вашем расширении протокола, потому что компилятор Swift не мог гарантировать, что соответствующие типы будут классами (даже если вы специально указали UIViewController). Поэтому я поставил class требование P1. Это сделал не работать.

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

если вы решили пойти по этому маршруту, пожалуйста, ответьте на этот вопрос (Swift 3 ObjC Optional Protocol метод не вызывается в подклассе) в счет. Похоже, что еще одна текущая проблема в Swift 3 заключается в том, что подклассы не делают автоматически наследовать реализации требований дополнительного протокола их суперкласса. Ответ на эти вопросы использует специальную адаптацию @objc чтобы обойти его.

сообщить о проблеме

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

обновление

в декабре 2016 года, этот вопрос сообщении для сообщества Swift. Вопрос по-прежнему помечен как открытый со средним приоритетом, но следующий комментарий был добавлено:

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

поскольку ваш протокол находится в том же модуле, что и ваше расширение, однако, вы можете сделать это в будущей версии Swift.

обновление 2

в феврале 2017 года этот вопрос был официально закрыт как "не будет делать" один из членов основной команды Swift со следующим сообщением:

это намеренно: расширения протокола не могут вводить точки входа @objc из-за ограничений среды выполнения Objective-C. Если вы хотите добавить точки входа @objc в NSObject, расширьте NSObject.

расширения NSObject или даже UIViewController не будут выполнять именно то, что вы хотите, но это к сожалению не похоже, что это станет возможным.

в (очень) долгосрочном будущем, мы можем быть в состоянии устранить зависимость от @objc методы полностью, но это время, скорее всего, не наступит в ближайшее время, так как рамки Cocoa в настоящее время не написаны в Swift (и не могут быть, пока у него не будет стабильного ABI).