非"@objc"方法不满足"@objc"协议的可选要求 [英] Non-'@objc' method does not satisfy optional requirement of '@objc' protocol
问题描述
- 我有一个协议P1,它提供了Objective-C可选功能之一的默认实现.
- 当我提供可选功能的默认实现时,会发出警告
Non-'@objc' method 'presentationController(_:viewControllerForAdaptivePresentationStyle:)' does not satisfy optional requirement of '@objc' protocol 'UIAdaptivePresentationControllerDelegate'
版本:
- 迅速:3
- Xcode:8(公开发布)
- Swift: 3
- Xcode: 8 (public release)
- 尝试添加
@objc
,但无济于事 - Tried adding
@objc
but doesn't help - 我该如何解决?
- 周围有工作吗?
Version:
@objc protocol P1 : UIAdaptivePresentationControllerDelegate {
}
extension P1 where Self : UIViewController {
func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
return UIViewController()
}
}
class A : UIViewController, P1 {
}
推荐答案
虽然我认为我可以回答您的问题,但这并不是您想要的答案.
While I think I can answer your question, it's not an answer you will like.
TL; DR: @objc
函数当前可能不在协议扩展中.您可以创建一个基类,尽管这不是理想的解决方案.
TL;DR: @objc
functions may not currently be in protocol extensions. You could create a base class instead, though that's not an ideal solution.
First, this question/answer (Can Swift Method Defined on Extensions on Protocols Accessed in Objective-c) seems to suggest that because of the way protocol extensions are dispatched under the hood, methods declared in protocol extensions are not visible to the objc_msgSend()
function, and therefore are not visible to Objective-C code. Since the method you are trying to define in your extension needs to be visible to Objective-C (so UIKit
can use it), it yells at you for not including @objc
, but once you do include it, it yells at you because @objc
is not allowed in protocol extensions. This is probably because protocol extensions are not currently able to be visible to Objective-C.
我们还可以看到添加@objc
后的错误消息指出"@objc只能与类的成员,@ objc协议和类的具体扩展一起使用."这不是一堂课; @objc协议的扩展名与协议定义本身(即在要求中)不同,并且"concrete"一词表示协议扩展名不算作具体的类扩展名.
We can also see that the error message once we add @objc
states "@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes." This is not a class; an extension to an @objc protocol is not the same as being in the protocol definition itself (i.e. in requirements), and the word "concrete" would suggest that a protocol extension does not count as a concrete class extension.
不幸的是,当默认实现必须对Objective-C框架可见时,这几乎完全阻止了您使用协议扩展.起初,我认为您的协议扩展中可能不允许使用@objc
,因为Swift编译器无法保证符合类型的是类(即使您已专门指定UIViewController
).因此,我在P1
上提出了class
要求.这没用.
Unfortunately, this pretty much completely prevents you from using protocol extensions when the default implementations must be visible to Objective-C frameworks. At first, I thought perhaps @objc
was not allowed in your protocol extension because the Swift Compiler could not guarantee that conforming types would be classes (even though you have specifically specified UIViewController
). So I put a class
requirement on P1
. This did not work.
也许唯一的解决方法是在这里简单地使用基类而不是协议,但这显然不是完全理想的,因为一个类可能只有一个基类,但符合多种协议.
Perhaps the only workaround is to simply use a base class instead of a protocol here, but this is obviously not completely ideal because a class may only have a single base class but conform to multiple protocols.
If you choose to go this route, please take this question (Swift 3 ObjC Optional Protocol Method Not Called in Subclass) into account. It appears that another current issue in Swift 3 is that subclasses do not automatically inherit the optional protocol requirement implementations of their superclass. The answer to that questions uses a special adaption of @objc
to get around it.
我认为在Swift开源项目中已经对此进行了讨论,但是您可以通过使用 Swift的Bug记者.但是,这两种方法都可能会发现您的错误范围太广或已知. Swift团队可能还会将您正在寻找的内容视为一项新的语言功能,在这种情况下,您应该先查看
I think this is being discussed already among those working on the Swift open source projects, but you could be sure they are aware by either using Apple's Bug Reporter, which would likely eventually make its way to the Swift Core Team, or Swift's bug reporter. Either of these may find your bug too broad or already known, however. The Swift team may also consider what you are looking for to be a new language feature, in which case you should first check out the mailing lists.
2016年12月,此问题已举报给Swift社区.该问题仍被标记为具有中等优先级的未解决问题,但是添加了以下注释:
In December 2016, this issue was reported to the Swift community. The issue is still marked as open with a medium priority, but the following comment was added:
这是有意的.没有方法可以向每个采用者添加该方法的实现,因为可以在符合协议之后添加扩展.我想如果扩展名与协议在同一模块中,我们可以允许它.
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.
但是,由于您的协议与扩展名在同一模块中,因此您可以在以后的Swift版本中做到这一点.
Since your protocol is in the same module as your extension, however, you may be able to do this in a future version of Swift.
2017年2月,此问题,并显示以下消息:
In February 2017, this issue was officially closed as "Won't Do" by one of the Swift Core Team members with the following message:
这是故意的:由于Objective-C运行时的限制,协议扩展不能引入@objc入口点.如果要将@objc入口点添加到NSObject,请扩展NSObject.
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
并不能完全实现您想要的功能,但是不幸的是,看起来并没有实现它的可能性.
Extending NSObject
or even UIViewController
will not accomplish exactly what you want, but it unfortunately does not look like it will become possible.
在(非常)长远的未来中,我们也许可以完全消除对@objc
方法的依赖,但是由于Cocoa框架当前不是用Swift编写的,所以时间可能不会很快到来.它具有稳定的ABI).
In the (very) long-term future, we may be able to eliminate reliance on @objc
methods entirely, but that time will likely not come anytime soon since Cocoa frameworks are not currently written in Swift (and cannot be until it has a stable ABI).
截止到2019年秋季,这已经成为一个问题,因为越来越多的Apple框架正在用Swift编写.例如,如果使用SwiftUI
而不是UIKit
,则可以完全避开该问题,因为在引用SwiftUI
方法时将永远不需要@objc
.
As of Fall 2019, this is becoming less of a problem because more and more Apple frameworks are being written in Swift. For example, if you use SwiftUI
instead of UIKit
, you sidestep the problem entirely because @objc
would never be necessary when referring to a SwiftUI
method.
用Swift编写的Apple框架包括:
Apple frameworks written in Swift include:
- SwiftUI
- RealityKit
- 组合
- CryptoKit
现在,随着Swift正式成为ABI和模块稳定版本(分别自Swift 5.0和5.1开始),人们会希望这种模式随着时间的流逝而持续下去.
One would expect this pattern to continue over time now that Swift is officially ABI and module stable as of Swift 5.0 and 5.1, respectively.
这篇关于非"@objc"方法不满足"@objc"协议的可选要求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!