首页 文章

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

提问于
浏览
111

我正在尝试将我的项目的源代码从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 标记,而且我没有必要使用'm assuming that' .

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


Related question:

4 回答

  • 8

    修复 - 它是正确的 - 您可以更改选择器,以使其引用的方法暴露给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() {
           // ... 
        }
    }
    

    (当选择了"minimise inference"选项运行时,迁移器应该使用选择器自动执行此操作)

    要将一组成员公开给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的所有成员,否则我不建议这样做,因为上面提到了让成员不必要地暴露的缺点 .

  • 15

    As Apple Official Documentation. you need to use @objc to call your Selector Method.

    在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) .

  • 141

    至于我认为Swift 4.2,您需要做的就是将@IBAction分配给您的方法,您可以避免这种愚蠢的@objc注释

    
    ```java
    let tap  =  UITapGestureRecognizer(target: self, action: #selector(self.cancel))
    
    
    @IBAction func cancel()
    {
        self.dismiss(animated: true, completion: nil)
    }
    
  • 0

    正如在其他答案中已经提到的那样,没有办法避免选择器的 @objc 注释 .

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

    • 转到 Build Settings

    • 搜索关键字 @objc

    • Swift 3 @objc interface 的值设置为 Off

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

    Silencing the warning "Swift 3 @objc interface"

    希望这可以帮助

相关问题