在 Swift 4中如何使用 # selector()处理@objecc 推断弃用?

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

例如,我使用常规选择器向按钮添加一个目标,如下所示:

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

这是它所显示的警告:

“ # selector”的参数引用“ ViewController”中的实例方法“ myAction ()”,该方法依赖于 Swift 4中不推荐的“@objecc”属性推断

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

现在,在错误消息上按 Fix会对我的函数造成这样的影响:

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


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

我真的不想重命名我的所有函数,以包括 @objc标记,我假设这是没有必要的。

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


相关问题:

48696 次浏览

修正-它是正确的-没有关于选择器的任何东西,您可以更改,以使它引用的方法暴露给 Objective-C。

这个警告的全部原因首先是 SE-0160的结果。在 Swift 4之前,NSObject继承类的 internal或更高的 Objective-C 兼容成员被推断为 @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,因为上面提到的不必要的暴露成员的缺点。

作为 苹果官方文件,您需要使用@objecc 来调用您的选择器方法。

在 Objective-C 中,选择器是一种引用 Objective-C 方法。在 Swift 中,Objective-C 选择器由 的 Selector结构,并可以使用 #selector 为可以从中调用的方法创建选择器 Objective-C,传递方法的名称,如 要为属性的 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注释。

但是,可以通过采取以下步骤来消除业务说明中提到的警告:

  1. 转到 生成设置
  2. 搜索关键字 @ objecc
  3. Swift 3@objecc 接口的值设置为 Off

下面是说明上述步骤的截图:

Silencing the warning "Swift 3 @objc interface"

希望这个能帮上忙

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

@IBAction func buttonAction() {


}

确保在故事板中连接这个插座。