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() { /* ... */ }