我正在尝试将项目的源代码从 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
标记,我认为这不是必需的。
如何重写选择器来处理弃用?
相关问题:
在 Swift 4 模式下使用 Swift 3 @objc 推理已被弃用?
@objc
is 以便将它们公开给 Obj-C,并因此与选择器一起使用。
@objc
?这有点烦人,但我通常将这些函数设为私有,无论如何都要求我将其标记为 @objc
。
@objcMembers
以便将所有与 Obj-C 兼容的成员公开给 Obj-C,但我不建议您这样做,除非您确实需要公开整个类。
修复它是正确的——您可以更改选择器以使其引用的方法暴露给 Objective-C 的任何内容。
这个警告的全部原因首先是 SE-0160 的结果。在 Swift 4 之前,NSObject
继承类的 internal
或更高版本的 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,因为上面提到的让成员不必要地暴露的缺点。
作为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)。
截至目前,我认为 Swift 4.2,您需要做的就是将 @IBAction
分配给您的方法并避免 @objc
注释。
let tap = UITapGestureRecognizer(target: self, action: #selector(self.cancel))
@IBAction func cancel()
{
self.dismiss(animated: true, completion: nil)
}
正如其他答案中已经提到的,没有办法避免选择器的 @objc
注释。
但是可以通过以下步骤消除 OP 中提到的警告:
转到 Build Settings 搜索关键字 @objc 将 Swift 3 @objc 接口的值设置为 Off
下面是说明上述步骤的屏幕截图:
https://i.stack.imgur.com/QNTKm.png
希望这可以帮助
如果您在视图控制器中需要目标 c 成员,只需在视图控制器顶部添加 @objcMembers。您可以通过在代码中添加 IBAction 来避免这种情况。
@IBAction func buttonAction() {
}
确保在情节提要中连接此插座。
不定期副业成功案例分享
@IBAction
是否也会自动@objc
?直到现在情况并非如此,但这是合乎逻辑的。编辑:nvm,提案明确指出@IBAction
足以使方法成为@objc
。