我正在尝试将项目的源代码从Swift 3转换为Swift4。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标记,并且我认为这不是必需的。

如何重写选择器以应对弃用?



相关问题:


The use of Swift 3 @objc inference in Swift 4 mode is deprecated?

最佳答案

修复程序是正确的-选择器没有任何改变,您可以更改以使其所引用的方法公开给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的成员生成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,因为上面提到的不必要地暴露成员的弊端。

关于swift - 在Swift 4中,如何使用#selector()处理@objc推理弃用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44465723/

10-12 00:11
查看更多