@selector() 在 Swift 中:ObjC 兼容性完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

什么是 Swift 中的 @selector() 以及为什么需要它?



如果您曾经使用过 Objective-C 或遇到过遗留代码,那么您一定听说过神奇的构造 @selector()。在 Swift 中,它转变为 #selector,但本质保持不变:它是 Swift 静态类型与 Objective-C 运行时动态特性之间的桥梁。



想象一下,您需要将方法的引用作为参数传递。例如,用于处理按钮点击或订阅通知。在 Swift 中,我们习惯使用闭包,但 Apple 的库(UIKit、AppKit、Foundation)仍然依赖老式的选择器机制。正是在这里,Swift 中的 @selector() 成为不可或缺的工具。



在本指南中,我们将介绍:

  • 如何在现代 Swift 中正确声明选择器
  • 典型错误以及如何避免它们
  • 来自 iOS 开发的实际示例
  • 何时使用 #selector,何时使用替代方案


从 @selector() 到 #selector:语法的演变



在 Objective-C 中,选择器看起来像这样:

[@selector(buttonTapped:)]


在 Swift 2.0 中,出现了 #selector 构造,并成为标准。现在看起来像这样:

#selector(MyClass.buttonTapped(_:))


关键区别:Swift 中的 #selector 由编译器检查。如果您拼错了方法名或传递了错误的签名,编译器会报错。与 Objective-C 相比,这是一个巨大的优势,在 Objective-C 中,选择器只是一个字符串,错误只会在运行时出现。



用于 #selector 的方法声明规则



传递给 #selector 的方法必须:

  • 可从 Objective-C 访问 — 使用 @objc 属性标记
  • 不是私有的(或标记为 @objc private)
  • 签名兼容 调用方所期望的签名


正确声明的示例:

class ViewController: UIViewController {    @objc func buttonTapped(_ sender: UIButton) {        print("按钮已点击!")    }        override func viewDidLoad() {        super.viewDidLoad()        let button = UIButton(type: .system)        button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)    }}


注意方法前的 @objc。没有它,编译器将不允许使用 #selector。



@selector() Swift:实际示例



1. Target-Action:按钮和手势



使用 #selector 最常见的场景是将操作绑定到 UI 元素:



class ProfileViewController: UIViewController {        @objc private func avatarTapped(_ gesture: UITapGestureRecognizer) {        print("头像被点击")    }        @objc private func settingsButtonPressed() {        print("打开设置")    }        override func viewDidLoad() {        super.viewDidLoad()                // 手势        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(avatarTapped(_:)))        avatarImageView.addGestureRecognizer(tapGesture)                // 按钮        settingsButton.addTarget(self, action: #selector(settingsButtonPressed), for: .touchUpInside)    }}


请记住:如果方法接受参数(例如 UITapGestureRecognizer),您必须在选择器签名中指定 _:#selector(avatarTapped(_:))。



2. PerformSelector 和延迟调用



有时需要动态调用方法,尤其是在使用 KVO 或定时器时:



class TimerManager {    @objc func fireTimer() {                

博客

书籍推荐