非'@objc' 方法不满足'@objc' 协议的可选要求 [英] Non-'@objc' method does not satisfy optional requirement of '@objc' protocol

查看:28
本文介绍了非'@objc' 方法不满足'@objc' 协议的可选要求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  • 我有一个协议 P1,它提供了一个 Objective-C 可选函数的默认实现.
  • 当我提供可选函数的默认实现时,会出现警告
Non-'@objc' method 'presentationController(_:viewControllerForAdaptivePresentationStyle:)' does not satisfy optional requirement of '@objc' protocol 'UIAdaptivePresentationControllerDelegate'

版本:

  • 斯威夫特:3
  • Xcode:8(公开发布)
    • 尝试添加 @objc 但没有帮助
    • Tried adding @objc but doesn't help
    • 我该如何解决这个问题?
    • 有解决办法吗?
    @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.

    首先,这个问题/答案(Can Swift Method Defined on Protocols Accessed in Objective-c) 似乎表明,由于协议扩展在后台调度的方式,协议扩展中声明的方法对 objc_msgSend 不可见() 函数,因此对 Objective-C 代码不可见.由于您尝试在扩展中定义的方法需要对 Objective-C 可见(以便 UIKit 可以使用它),因此它会因为不包括 @objc 而对您大吼大叫,但是一旦你包含它,它就会对你大吼大叫,因为 @objc 在协议扩展中是不允许的.这可能是因为 Objective-C 目前无法看到协议扩展.

    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 协议的扩展与协议定义本身(即在需求中)不同,具体"一词表示协议扩展不算作具体的类扩展.

    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.

    如果你选择走这条路,请回答这个问题(Swift 3 ObjC 可选协议方法未在子类中调用) 考虑在内.Swift 3 中的另一个当前问题似乎是子类不会自动继承其超类的可选协议要求实现.这些问题的答案使用了 @objc 的特殊改编来解决它.

    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 开源项目的工作人员中进行了讨论,但是您可以通过使用 Apple 的错误报告者,最终可能会进入 Swift 核心团队,或者 Swift 的错误报告者一>.但是,其中任何一个都可能会发现您的错误过于广泛或已经为人所知.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 月,这个问题 被 Swift 核心团队成员之一正式关闭为不会做",并带有以下消息:

    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 入口点.如果你想给 NSObject 添加 @objc 入口点,扩展 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,你就完全回避了这个问题,因为在引用 @objc 时永远不需要>SwiftUI 方法.

    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 分别从 Swift 5.0 和 5.1 开始正式 ABI 和模块稳定,因此人们预计这种模式会随着时间的推移而继续.

    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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆