处理Swift 4 使用#selector警告:Argument of '#selector' refers to instance method that depends on '@objc' attribute inference deprecated in Swift 4

时间:2022-06-01 12:56:14

Swift 3升级到Swift 4,在使用#selector可能会报以下警告:

Argument of '#selector' refers to instance method 'doAction()' in 'ViewController' that depends on '@objc' attribute inference deprecated in Swift 4

原因

如果需要把Swift API暴露给Objective-C,我们需要添加@objc注解。Swift 3以及之前的版本,为了达到最大兼容Objective-C,编译器会在很多地方隐式地添加了@objc,例如所有继承于NSObject的类都会被自动加上@objc。

显然我们很多时候并不需要暴露Swift的API给Objective-C,这些隐式转换给app的包添加了额外的代码。

Swift 4对此做出了调整,NSObject的子类不再自动添加@objc。只有以下这几种情况才会隐式推断为@objc:

  • 重写@objc的声明
class Super {
    @objc func foo() { }
}

class Sub : Super {
    /* 推断为 @objc */
    override func foo() { }
}
  • 实现@objc协议要求的声明
@objc protocol MyDelegate {
    func bar()
}

class MyClass : MyDelegate {
    /* 推断为 @objc */
    func bar() { }
}
  • 声明中属性隐含了@objc,例如@IBAction,@IBOutlet和@NSManaged

其他情况Swift 4要求我们显式添加@objc到那些需要暴露给Objective-C的API。

显式暴露Swift API

使用@objc标记单独的方法

@objc func myFunc() {
   // ... 
}

使用@objc标记多个方法

@objc extension ViewController {
    func objcMethod1() {}
    func objcMethod2() {}
    @nonobjc nonObjcMethod() {}
}

如果不需要暴露的方法,使用@nonobjc标记

使用@objcMembers标记整个类或struct

@objcMembers class ViewController: UIViewController {
    // code
}

问题解决

上面的问题就是需要我们显示添加@objc来解决。

func doAction() { /* ... */ }

// 改为
@objc func doAction() { /* ... */ }

参考:SE-0160:Limiting @objc inference