概述:
编译器警告:
Non-'@objc' method 'presentationController(_:viewControllerForAdaptivePresentationStyle:)' does not satisfy optional requirement of '@objc' protocol 'UIAdaptivePresentationControllerDelegate'
版本:
做出的尝试:
@objc
但无济于事 问题:
代码:
@objc protocol P1 : UIAdaptivePresentationControllerDelegate {
}
extension P1 where Self : UIViewController {
func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
return UIViewController()
}
}
class A : UIViewController, P1 {
}
最佳答案
虽然我想我可以回答你的问题,但这不是你会喜欢的答案。
TL;博士: @objc
功能目前可能不在协议(protocol)扩展中。您可以改为创建基类,尽管这不是理想的解决方案。
协议(protocol)扩展和 Objective-C
首先,这个问题/答案( Can Swift Method Defined on Extensions on Protocols Accessed in Objective-c )似乎表明,由于协议(protocol)扩展在后台调度的方式,协议(protocol)扩展中声明的方法对 objc_msgSend()
不可见。函数,因此对 Objective-C 代码不可见。由于您尝试在扩展中定义的方法需要对 Objective-C 可见(因此 UIKit
可以使用它),因此它会因为不包括 @objc
而对您大喊大叫。 ,但是一旦您包含它,它就会对您大喊大叫,因为 @objc
不允许在协议(protocol)扩展中使用。这可能是因为协议(protocol)扩展目前对 Objective-C 不可见。
我们还可以看到添加 @objc
后的错误信息声明“@objc 只能与类的成员、@objc 协议(protocol)和类的具体扩展一起使用。”这不是一个类; @objc 协议(protocol)的扩展与协议(protocol)定义本身(即在需求中)不同,“具体”一词表明协议(protocol)扩展不算作具体的类扩展。
解决方法
不幸的是,当默认实现必须对 Objective-C 框架可见时,这几乎完全阻止了您使用协议(protocol)扩展。起初,我想也许是@objc
不允许在您的协议(protocol)扩展中使用,因为 Swift 编译器无法保证符合的类型是类(即使您明确指定了 UIViewController
)。所以我放了一个 class
要求 P1
.这没有用。
也许唯一的解决方法是在这里简单地使用基类而不是协议(protocol),但这显然不是完全理想的,因为一个类可能只有一个基类但符合多个协议(protocol)。
如果你选择走这条路,请考虑这个问题(Swift 3 ObjC Optional Protocol Method Not Called in Subclass)。 Swift 3 中的另一个当前问题似乎是子类不会自动继承其父类(super class)的可选协议(protocol)要求实现。该问题的答案使用了 @objc
的特殊改编。绕过它。
报告问题
我认为这已经在 Swift 开源项目的工作人员中进行了讨论,但是您可以通过使用 Apple's Bug Reporter 来确定他们知道这一点。 ,这可能最终会进入 Swift 核心团队,或者 Swift's bug reporter .但是,这些中的任何一个都可能会发现您的错误过于广泛或已经为人所知。 Swift 团队可能还会考虑您正在寻找的新语言功能,在这种情况下,您应该首先查看 the mailing lists .
更新
2016年12月,本期was reported到 Swift 社区。该问题仍被标记为具有中等优先级的未解决,但添加了以下评论:
This is intended. There is no way to add the implementation of the method to every adopter, since the extension could be added after the conformance to the protocol. I suppose we could allow it if the extension is in the same module as the protocol, though.
但是,由于您的协议(protocol)与您的扩展位于同一模块中,因此您可以在 future 版本的 Swift 中执行此操作。
更新 2
2017年2月,本期was officially closed作为 Swift 核心团队成员之一的“不会做”,并带有以下消息:
This is intentional: protocol extensions cannot introduce @objc entry points due to limitations of the Objective-C runtime. If you want to add @objc entry points to NSObject, extend NSObject.
扩展
NSObject
甚至 UIViewController
不会完全完成你想要的,但不幸的是它看起来不可能。在(非常)长期的 future ,我们或许能够消除对
@objc
的依赖。方法完全,但那个时间可能不会很快到来,因为 Cocoa 框架目前不是用 Swift 编写的(并且在它有一个稳定的 ABI 之前不可能)。更新 3
到 2019 年秋季,这不再是一个问题,因为越来越多的 Apple 框架是用 Swift 编写的。例如,如果您使用
SwiftUI
而不是 UIKit
,你完全回避了这个问题,因为 @objc
引用 SwiftUI
时永远没有必要方法。用 Swift 编写的 Apple 框架包括:
由于 Swift 分别从 Swift 5.0 和 5.1 开始正式 ABI 和模块稳定,人们预计这种模式会随着时间的推移而继续。
关于swift - 非 -'@objc' 方法不满足 '@objc' 协议(protocol)的可选要求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39487168/