Swift4中如何不使用Objective-C为Label添加点击事件
问题描述
我目前有一段Objective-C风格的代码,用于给Label(hashTag.hashTag1)添加点击事件,触发后通过通知中心跳转到其他页面并传递数据。代码可以正常运行,但我希望完全移除Objective-C及NS相关函数,改为纯Swift 4实现。
现有代码
Objective-C风格的处理函数
@objc func handleTapHash(gestureRecognizer: UIGestureRecognizer) { NotificationCenter.default.post(name: NSNotification.Name("ViewerOfHash"), object: nil) } @objc func ViewerOfHash() { performSegue(withIdentifier: "ViewerOfHash", sender: nil) PassDataController.addData(newData: "12300") MainVC.tof = 1 }
给Label添加点击事件的代码
let gestureRecognizer1 = UITapGestureRecognizer(target: self, action: #selector(self.handleTapHash)) hashTag.hashTag1.addGestureRecognizer(gestureRecognizer1)
需求
完全不使用Objective-C及NS相关函数,通过Label点击向另一个页面传递数据,改为纯Swift 4实现。
纯Swift 4实现方案
我给你整理了两种纯Swift的改造思路,第二种更简洁直接,推荐优先使用:
方案一:保留通知逻辑,替换OC相关写法
如果想保留原有的通知中转逻辑,我们可以从这几个点改造:
用Swift闭包替代@objc手势方法
给UITapGestureRecognizer写个小扩展,让它支持闭包回调,彻底摆脱@objc标记:extension UITapGestureRecognizer { convenience init(tapHandler: @escaping (UITapGestureRecognizer) -> Void) { self.init() self.addTarget(self, action: #selector(handleTap(_:))) self.tapHandler = tapHandler } private struct AssociatedKeys { static var tapHandler = "tapHandler" } private var tapHandler: ((UITapGestureRecognizer) -> Void)? { get { return objc_getAssociatedObject(self, &AssociatedKeys.tapHandler) as? ((UITapGestureRecognizer) -> Void) } set { objc_setAssociatedObject(self, &AssociatedKeys.tapHandler, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } @objc private func handleTap(_ gesture: UITapGestureRecognizer) { tapHandler?(gesture) } }注:这里的
objc_getAssociatedObject是Swift关联对象的标准用法,不属于业务层面的OC依赖,是实现闭包回调的必要手段。用Swift风格的通知名称
替换原有的字符串字面量通知名,用类型安全的静态属性定义:extension Notification.Name { static let viewerOfHash = Notification.Name("ViewerOfHash") }移除@objc的通知处理方法
用Swift的闭包式观察者替代@objc方法:override func viewDidLoad() { super.viewDidLoad() // 添加通知观察者 NotificationCenter.default.addObserver(forName: .viewerOfHash, object: nil, queue: .main) { [weak self] _ in guard let self = self else { return } self.performSegue(withIdentifier: "ViewerOfHash", sender: nil) PassDataController.addData(newData: "12300") MainVC.tof = 1 } // 给Label添加点击手势 let gestureRecognizer1 = UITapGestureRecognizer { [weak self] _ in guard let self = self else { return } NotificationCenter.default.post(name: .viewerOfHash, object: nil) } hashTag.hashTag1.isUserInteractionEnabled = true // 必须开启Label交互! hashTag.hashTag1.addGestureRecognizer(gestureRecognizer1) }
方案二:直接跳转(更简洁推荐)
其实点击Label后直接跳转页面完全不需要通知中转,这种方式代码更简洁,也完全是纯Swift实现:
override func viewDidLoad() { super.viewDidLoad() // 给Label添加点击手势,直接处理跳转和传参 let gestureRecognizer1 = UITapGestureRecognizer { [weak self] _ in guard let self = self else { return } // 把要传递的数据作为sender传入segue self.performSegue(withIdentifier: "ViewerOfHash", sender: "12300") MainVC.tof = 1 } hashTag.hashTag1.isUserInteractionEnabled = true hashTag.hashTag1.addGestureRecognizer(gestureRecognizer1) } // 在segue准备阶段传递数据到目标页面 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "ViewerOfHash", let data = sender as? String { PassDataController.addData(newData: data) // 更推荐的方式是直接给目标VC的属性赋值,比如: // if let targetVC = segue.destination as? TargetViewController { // targetVC.receivedData = data // } } }
关键注意点
- 一定要给Label设置
isUserInteractionEnabled = true,否则点击手势不会生效。 - 使用
[weak self]避免循环引用,这是Swift内存管理的最佳实践。
内容的提问来源于stack exchange,提问作者Soonmyun Jang
相关产品推荐
相关产品推荐

