虽然我认为我可以回答您的问题,但这不是您想要的答案。
TL; DR: @objc
功能可能当前不在协议扩展中。您可以创建一个基类,尽管这不是理想的解决方案。
协议扩展和Objective-C
首先,这个问题/答案(可以在Objective-c中访问的协议扩展上定义了Swift方法)似乎表明,由于协议扩展是在后台分发的,该objc_msgSend()
函数中看不到协议扩展中声明的方法,并且因此对Objective-C代码不可见。由于您要在扩展中定义的方法需要对Objective-C可见(因此UIKit
可以使用),因此对您大吼大叫不包括@objc
,但是一旦您将其包括@objc
进来,它便对您大吼,因为不允许协议扩展。这可能是因为协议扩展当前对Objective-C不可见。
我们还可以看到,一旦添加了@objc
状态“ @objc只能与类的成员,@ objc协议和类的具体扩展一起使用” ,该错误消息就会出现。这不是一堂课。@objc协议的扩展名与协议定义本身(即在要求中)不同,并且单词“ concrete”将暗示协议扩展名不算作具体的类扩展名。
解决方法
不幸的是,当默认实现必须对Objective-C框架可见时,这几乎完全阻止您使用协议扩展。刚开始,我认为@objc
您的协议扩展中可能不允许这样做,因为Swift编译器无法保证符合类型的是类(即使您已明确指定UIViewController
)。因此,我对提出了class
要求P1
。这没有用。
也许唯一的解决方法是在这里简单地使用基类而不是协议,但这显然不是完全理想的,因为一个类可能只有一个基类,但符合多个协议。
如果您选择走这条路线,请考虑以下问题(在子类中未调用Swift 3 ObjC可选协议方法)。看来,Swift 3中的另一个当前问题是子类不会自动继承其超类的可选协议要求实现。该问题的答案使用特殊的改编@objc
来解决。
报告问题
我认为这已经在Swift开源项目的开发人员中进行了讨论,但是您可以肯定使用Apple的Bug Reporter(可能最终会进入Swift核心团队)或Swift的Bug记者了解他们的情况。但是,这两种方法都可能会发现您的错误范围太广或已知。Swift团队可能还会将您正在寻找的内容视为一项新的语言功能,在这种情况下,您应该先查看邮件列表。
更新资料
2016年12月,此问题已报告给Swift社区。该问题仍被标记为具有中等优先级的未解决问题,但是添加了以下注释:
这是有意的。无法将方法的实现添加到每个采用者,因为扩展可以在符合协议之后添加。我想如果扩展名与协议在同一个模块中,我们可以允许它。
由于您的协议与扩展名在同一个模块中,因此您可以在以后的Swift版本中执行此操作。
更新2
2017年2月,Swift核心团队的成员之一以“ Wo n't Do” 正式关闭了此问题,并显示以下消息:
这是故意的:由于Objective-C运行时的限制,协议扩展不能引入@objc入口点。如果要将@objc入口点添加到NSObject,请扩展NSObject。
扩展NSObject
甚至UIViewController
无法完全实现您想要的功能,但是不幸的是,它看起来并没有成为可能。
在(非常长远的)将来,我们也许可以@objc
完全消除对方法的依赖,但是由于Cocoa框架当前不是用Swift编写的,所以可能很快就不会出现(并且直到它具有稳定的ABI时)。 。
更新3
截至2019年秋季,这已经成为一个问题,因为越来越多的Apple框架正在用Swift编写。例如,如果您使用SwiftUI
而不是UIKit
,那么您将完全避开该问题,因为@objc
在引用SwiftUI
方法时将永远不需要。
用Swift编写的Apple框架包括:
现在,随着Swift正式成为ABI和模块稳定版本(分别自Swift 5.0和5.1开始),人们可能会希望这种模式会随着时间的推移而持续下去。
@objc