iOS 介绍

示例

通常,当使用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()
    }
}