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

时间:2017-06-06 12:44:48

标签: swift xcode swift4

我正在尝试将我的项目源代码从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标记,我假设没有必要。

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

相关问题:

5 个答案:

答案 0 :(得分:149)

修复 - 它是正确的 - 您可以更改选择器,以使其引用的方法暴露给Objective-C。

首先出现此警告的全部原因是SE-0160的结果。在Swift 4之前,internal或更高的NSObject继承类的Objective-C兼容成员被推断为@objc,因此暴露给Objective-C,因此允许使用选择器调用它们(因为需要Obj-C运行时才能查找给定选择器的方法实现)。

然而在Swift 4中,情况已不再如此。现在只推断非常具体的声明为@objc,例如,@objc方法的覆盖,@objc协议要求的实现和具有暗示@objc的属性的声明,例如@IBOutlet

这背后的动机,如详细in the above linked proposal,首先是防止NSObject继承类中的方法重载由于具有相同的选择器而相互冲突。其次,它不需要为不需要暴露给Obj-C的成员生成thunks,从而有助于减少二进制大小,第三,提高了动态链接的速度。

如果要将成员公开给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的所有成员,因为上面提到了让成员不必要地暴露的缺点。

答案 1 :(得分:16)

作为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)

答案 2 :(得分:8)

从现在开始,我认为Swift 4.2只需将@IBAction分配给您的方法,就可以避免使用这种愚蠢的@objc注释

```

let tap  =  UITapGestureRecognizer(target: self, action: #selector(self.cancel))


@IBAction func cancel()
{
    self.dismiss(animated: true, completion: nil)
}

答案 3 :(得分:1)

正如其他答案中已经提到的那样,无法避免为选择器使用@objc注释。

但是可以通过执行以下步骤来消除OP中提到的警告:

  1. 转到构建设置
  2. 搜索关键字 @objc
  3. Swift 3 @objc接口的值设置为Off

下面的屏幕快照说明了上述步骤:

Silencing the warning "Swift 3 @objc interface"

希望这会有所帮助

答案 4 :(得分:1)

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

@IBAction func buttonAction() {

}

确保将此插座连接到情节提要中。