【问题标题】:How can I deal with @objc inference deprecation with #selector() in Swift 4?如何在 Swift 4 中使用 #selector() 处理 @objc 推理弃用?
【发布时间】:2017-11-07 11:48:56
【问题描述】:

我正在尝试将项目的源代码从 Swift 3 转换为 Swift 4。Xcode 给我的一个警告是关于我的选择器。

例如,我使用这样的常规选择器将目标添加到按钮:

button.addTarget(self, action: #selector(self.myAction), for: .touchUpInside)

这是它显示的警告:

“#selector”的参数指的是“ViewController”中的实例方法“myAction()”,它依赖于 Swift 4 中已弃用的“@objc”属性推断

添加“@objc”以将此实例方法公开给 Objective-C

现在,在错误消息上点击 Fix 会对我的函数执行以下操作:

// before
func myAction() { /* ... */ }

// after
@objc func myAction() { /* ... */ }

我真的不想重命名我的所有函数以包含 @objc 标记,我认为这没有必要。

如何重写选择器来处理弃用?


相关问题:

【问题讨论】:

  • 不,将它们标记为@objc 现在必须将它们公开给Obj-C,因此与选择器一起使用。
  • 所以不推荐使用的部分将公共访问功能推断为@objc?这有点烦人,但我通常将这些函数设为私有,无论如何都要求我将其标记为 @objc
  • 请参阅SE-0160 了解有关更改的更多信息。另一种选择是将给定的类标记为@objcMembers,以便将所有与 Obj-C 兼容的成员公开给 Obj-C,但我不建议这样做,除非您确实需要公开整个类。
  • @LinusGeffarth 正如提案中所说,它可能会不必要地增加二进制文件的大小,并且动态链接会花费更长的时间。我真的不认为对于从 Obj-C 中使用的特定事物特别意味着增加的清晰度来说太麻烦了。
  • 试过了,不行。

标签: swift xcode swift4


【解决方案1】:

截至目前,我认为 Swift 4.2,您所需要做的就是将 @IBAction 分配给您的方法并避免使用 @objc 注释。

let tap  =  UITapGestureRecognizer(target: self, action: #selector(self.cancel))

@IBAction func cancel()
{
    self.dismiss(animated: true, completion: nil)
}

【讨论】:

  • 这也会告诉界面生成器这个函数可以连接,这可能不是你想要的。它也和@objc 做同样的事情。
【解决方案2】:

如果您在视图控制器中需要目标 c 成员,只需在视图控制器顶部添加 @objcMembers。您可以通过在代码中添加 IBAction 来避免这种情况。

@IBAction func buttonAction() {

}

确保在情节提要中连接此插座。

【讨论】:

    【解决方案3】:

    正如其他答案中已经提到的,没有办法避免选择器的 @objc 注释。

    但可以通过以下步骤消除 OP 中提到的警告:

    1. 转到构建设置
    2. 搜索关键字@objc
    3. Swift 3 @objc interface的值设置为Off

    以下是说明上述步骤的屏幕截图:

    希望对你有帮助

    【讨论】:

    • 这对您的项目有何影响?
    • *.ipa 或 *.xarchive 的大小和构建时间如何?
    • @ZonilyJame 我没有注意到构建时间,但对 IPA 大小没有影响
    • 如果您按照 Apple 指南使用 swift 4.0+ 版本,这不是您可以使用的推荐值。检查这个help.apple.com/xcode/mac/current/#/deve838b19a1
    • 您可以通过在 Xcode 11 中将值设置为 Default 来更新此答案。在项目和目标上设置值以完全消除警告非常重要。
    【解决方案4】:

    解决方法是正确的 - 选择器没有任何内容可以更改以使其引用的方法暴露给 Objective-C。

    这个警告的全部原因首先是SE-0160 的结果。在 Swift 4 之前,internal 或更高版本的 NSObject 继承类的 Objective-C 兼容成员被推断为 @objc 并因此暴露给 Objective-C,因此允许使用选择器调用它们(作为 Obj-C需要运行时才能查找给定选择器的方法实现)。

    但在 Swift 4 中,情况不再如此。现在只有非常具体的声明被推断为@objc,例如,@objc 方法的覆盖、@objc 协议要求的实现以及带有暗示@objc 的属性的声明,例如@IBOutlet

    这背后的动机,详细in the above linked proposal,首先是为了防止NSObject继承类中的方法重载由于具有相同的选择器而相互冲突。其次,它不必为不需要暴露给 Obj-C 的成员生成 thunk,从而有助于减少二进制文件的大小,第三,提高了动态链接的速度。

    如果要将成员暴露给Obj-C,则需要将其标记为@objc,例如:

    class ViewController: UIViewController {
    
        @IBOutlet weak var button: UIButton!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            button.addTarget(self, action: #selector(foo), for: .touchUpInside)
        }
    
        @objc func foo() {
           // ... 
        }
    }

    (在选择“最小化推理”选项运行时,迁移器应该使用选择器自动为您执行此操作)

    要将一组成员公开给 Obj-C,您可以使用 @objc extension

    @objc extension ViewController {
    
        // both exposed to Obj-C
        func foo() {}
        func bar() {}
    }
    

    这会将其中定义的所有成员公开给 Obj-C,并对任何不能公开给 Obj-C 的成员给出错误(除非明确标记为 @nonobjc)。

    如果你有一个类需要所有 Obj-C 兼容的成员暴露给 Obj-C,你可以将该类标记为@objcMembers

    @objcMembers
    class ViewController: UIViewController {
       // ...
    }
    

    现在,所有可以推断为@objc 的成员都将是。但是,除非您真的需要所有成员都暴露于 Obj-C,否则我不建议这样做,因为上面提到的让成员不必要地暴露的缺点。

    【讨论】:

    • 为什么 Xcode 在将代码转换为最新语法时不会自动执行此操作?
    • 我想知道,@IBAction 是否也会自动@objc?直到现在情况并非如此,但这是合乎逻辑的。编辑:nvm,提案明确指出@IBAction 足以让方法成为@objc
    • 我什么都不懂。我从来没有Objective-C代码。是否没有纯粹的 Swift 方式将目标添加到按钮?还是使用选择器?我不希望我的代码充满这个属性。是不是因为 UIButton 是从一些 NSObject/Obj-c-thing 派生的?
    • @Sti 所以直接回答“没有纯粹的 Swift 方式向按钮添加目标吗?或者使用选择器?”——不,没有“纯粹的 Swift " 使用选择器分派给方法的方式。他们依靠 Obj-C 运行时来查找方法实现以调用特定的选择器——Swift 运行时没有这种能力。
    • 男人选择器一团糟。似乎他们正在搞乱它的所有其他快速更新。为什么我们不能只为方法提供一个纯粹的快速自动完成选择器。让代码看起来很丑。
    【解决方案5】:

    作为Apple Official Documentation。你需要使用@objc 来调用你的选择器方法。

    在 Objective-C 中,选择器是一种引用对象名称的类型 Objective-C 方法。在 Swift 中,Objective-C 选择器由 Selector 结构,并且可以使用 #selector 构造 表达。为可以调用的方法创建选择器 Objective-C,传递方法名,如 #selector(MyViewController.tappedButton(sender:))。要为属性的 Objective-C getter 或 setter 方法构造选择器,请通过 以getter:setter: 标签为前缀的属性名称,例如 #selector(getter: MyViewController.myButton).

    【讨论】:

    • 我从中了解到的是,在某些情况下,无论我是否打算从 Objective-C 调用它,我都需要将 @objc 添加到 func 的开头。我刚刚学习 Swift,已经使用 Obj-C 多年了
    猜你喜欢
    • 2018-04-19
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 2022-11-20
    • 1970-01-01
    • 1970-01-01
    • 2019-04-07
    相关资源
    最近更新 更多