修复它是正确的——您可以更改选择器以使其引用的方法暴露给 Objective-C 的任何内容。
这个警告的全部原因首先是SE-0160的结果。在 Swift 4 之前,继承类的internal
或更高版本的 Objective-C 兼容成员NSObject
被推断为@objc
并因此暴露给 Objective-C,因此允许使用选择器调用它们(因为需要 Obj-C 运行时才能查找方法给定选择器的实现)。
但是在 Swift 4 中,情况不再如此。现在只有非常具体的声明被推断为@objc
,例如,@objc
方法的覆盖、@objc
协议要求的实现和具有隐含属性的声明@objc
,例如@IBOutlet
.
这背后的动机,如上面链接的提案中所详述,首先是为了防止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,否则我不建议这样做,因为上面提到的让成员不必要地暴露的缺点。