通常,当使用UIControl或时UIButton,我们selector为按钮或控件上发生事件(例如用户按下按钮或触摸控件)的事件添加一个回调动作。
例如,我们将执行以下操作:
import UIKit class ViewController: UIViewController { @IBOutlet weak var button: UIButton! override func viewDidLoad() { super.viewDidLoad() let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 44)) button.addTarget(self, action: #selector(self.onButtonPress(_:)), for: .touchUpInside) self.view.addSubview(button) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func onButtonPress(_ button: UIButton!) { print("PRESSED") } }
涉及到时selector,编译器只需要知道它的存在即可protocol。
例如,以下内容将使您的应用程序崩溃:
import UIKit @objc protocol ButtonEvent { @objc optional func onButtonPress(_ button: UIButton) } class ViewController: UIViewController, ButtonEvent { @IBOutlet weak var button: UIButton! override func viewDidLoad() { super.viewDidLoad() let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 44)) button.addTarget(self, action: #selector(ButtonEvent.onButtonPress(_:)), for: .touchUpInside) self.view.addSubview(button) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
这是因为您的应用程序未实现该onButtonPress功能。
现在,如果您可以在初始化按钮的同时做所有这些事情呢?如果您不必指定回调,而可以指定可以随时添加和删除的块,该怎么办?为什么要担心实现选择器?
解
import Foundation import UIKit protocol RemovableTarget { func enable(); func disable(); } extension UIControl { func addEventHandler(event: UIControlEvents, runnable: (control: UIControl) -> Void) -> RemovableTarget { class Target : RemovableTarget { private var event: UIControlEvents private weak var control: UIControl? private var runnable: (control: UIControl) -> Void private init(event: UIControlEvents, control: UIControl, runnable: (control: UIControl) -> Void) { self.event= event self.control= control self.runnable= runnable } @objc private func run(_ control: UIControl) { runnable(control: control) } private func enable() { control?.addTarget(self, action: #selector(Target.run(_:)), for: event) objc_setAssociatedObject(self, unsafeAddress(of: self), self, .OBJC_ASSOCIATION_RETAIN) } private func disable() { control?.removeTarget(self, action: #selector(Target.run(_:)), for: self.event) objc_setAssociatedObject(self, unsafeAddress(of: self), nil, .OBJC_ASSOCIATION_ASSIGN) } } let target = Target(event: event, control: self, runnable: runnable) target.enable() return target } }
上面是对的简单扩展UIControl。它添加一个内部私有类,该类具有一个func run(_ control: UIControl)用作事件动作的回调。
接下来,我们使用object association添加和删除目标,因为不会保留目标UIControl。
该事件处理函数返回Protocol以隐藏的内部工作Target类,但也让你enable和disable在任何给定时间的目标。
用法示例:
import Foundation import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //创建一个按钮。 let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 44)) //添加事件动作块/侦听器-按下处理按钮。 let target = button.addEventHandler(event: .touchUpInside) { (control) in print("Pressed") } self.view.addSubview(button) //启用/禁用侦听器/事件动作块的示例。 DispatchQueue.main.after(when: DispatchTime.now() + 5) { target.disable() //禁用监听器。 DispatchQueue.main.after(when: DispatchTime.now() + 5) { target.enable() //启用监听器。 } } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }