非'@ objc'方法不满足'@objc'协议的可选要求

use*_*037 90 swift swift-protocols swift3

概述:

  • 我有一个协议P1,它提供了Objective-C可选功能之一的默认实现.
  • 当我提供可选功能的默认实现时,会出现警告

编译器警告:

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

版:

  • 斯威夫特:3
  • Xcode:8(公开发布)

尝试:

  • 尝试添加@objc但没有帮助

题:

  • 我该如何解决这个问题?
  • 有工作吗?

码:

@objc protocol P1 : UIAdaptivePresentationControllerDelegate {

}

extension P1 where Self : UIViewController {

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


class A : UIViewController, P1 {

}
Run Code Online (Sandbox Code Playgroud)

Mat*_*man 166

虽然我想我可以回答你的问题,但这不是你想要的答案.

TL; DR: @objc函数当前可能不在协议扩展中.您可以改为创建一个基类,尽管这不是一个理想的解决方案.

协议扩展和Objective-C

首先,这个问题/答案(可以在Objective-c中访问的协议的扩展上定义的Swift方法)似乎表明,由于协议扩展的方式是在引擎下发送的,协议扩展中声明的方法对于objc_msgSend()函数是不可见的,并且因此,Objective-C代码不可见.由于您尝试在扩展中定义的方法需要对Objective-C可见(因此UIKit可以使用它),它会因为不包括@objc而对您大喊大叫,但是一旦您确实包含它,它会因为@objc不允许而对您大喊大叫协议扩展.这可能是因为Objective-C当前无法看到协议扩展.

我们还可以看到,一旦我们添加了错误消息,@objc状态"@objc只能用于类的成员,@ objc协议和类的具体扩展." 这不是一个阶级; @objc协议的扩展与协议定义本身(即需求中)的扩展不同,"具体"一词表示协议扩展不算作具体的类扩展.

解决方法

不幸的是,当Objective-C框架必须可以看到默认实现时,这几乎完全阻止了您使用协议扩展.起初,我认为可能@objc在你的协议扩展中不允许,因为Swift编译器不能保证符合类型的类是类(即使你已经明确指定UIViewController).所以我提出了class要求P1.这没用.

也许唯一的解决方法是在这里简单地使用基类而不是协议,但这显然不是完全理想的,因为类可能只有一个基类但符合多个协议.

如果您选择此路线,请考虑此问题(Swift 3 ObjC可选协议方法未在子类中调用).似乎Swift 3中的另一个当前问题是子类不会自动继承其超类的可选协议要求实现.这些问题的答案使用了一种特殊的适应性@objc来绕过它.

报告问题

我认为在Swift开源项目中已经有人讨论过这个问题了,但你可以肯定他们都知道使用Apple的Bug Reporter,它最终可能会进入Swift核心团队,或者Swift的bug报告者.但是,这些中的任何一个都可能发现您的错误太广泛或已知.雨燕的团队也可以考虑你在找什么是新的语言功能,在这种情况下,你应该首先检查了邮件列表.

更新

2016年12月,向Swift社区报告了此问题.该问题仍标记为具有中等优先级的开放,但添加了以下注释:

这是有意的.没有办法将方法的实现添加到每个采用者,因为可以在符合协议之后添加扩展.我想如果扩展名与协议在同一个模块中,我们可以允许它.

但是,由于您的协议与扩展程序位于同一模块中,因此您可以在将来的Swift版本中执行此操作.

更新2

2017年2月,Swift核心团队成员之一正式关闭此问题为"Will not Do",并发出以下消息:

这是故意的:由于Objective-C运行时的限制,协议扩展不能引入@objc入口点.如果要将@objc入口点添加到NSObject,请扩展NSObject.

延伸NSObject甚至UIViewController不会完全达到你想要的效果,但遗憾的是它看起来不会成为可能.

在(非常)长期的未来,我们或许能够@objc完全消除对方法的依赖,但是由于Cocoa框架目前不是用Swift编写的(并且直到它具有稳定的ABI),因此该时间很可能不会很快到来. .

  • 您是正确的,尽管“ Swift 4”至今没有其他替代方法,您的答案仍然有效。 (2认同)
  • 我有一段时间完全相同的代码为我工作,但在后来的 Xcode 版本中被打破了。这相当令人气愤。Objective-C 协议中有很多可选方法。 (2认同)

CMa*_*ash 5

我刚刚在我使用的 swift 框架中启用“模块稳定性”(打开“构建分发库”)后遇到了这个问题。

我所拥有的是这样的:

class AwesomeClass: LessAwesomeClass {
...
}

extension AwesomeClass: GreatDelegate {
  func niceDelegateFunc() {
  }
}
Run Code Online (Sandbox Code Playgroud)

扩展中的函数存在以下错误:

  • “LessAwesomeClass”子类扩展中的“@objc”实例方法需要 iOS 13.0.0

  • 非“@objc”方法“niceDelegateFunc”不满足“@objc”协议“GreatDelegate”的要求

将函数移到类中而不是扩展中解决了这个问题。