开发笔记-Swift

使用 Block 处理 UIControl 的各种事件

2019-08-23  本文已影响0人  周胖儿

由于 UIControl 的消息事件是基于 action-target 机制的。所以在添加一个事件的处理代码时,通常会这么做:

  1. 将处理方法与控件关联。
ctl.addTarget(self, action: #selector(onTouchUpInside), for: .touchUpInside)
  1. 实现处理方法
@objc func onTouchUpInside(control: UIControl) {
    print("事件的处理代码")
}

很显然,这种方法非常啰嗦,平白增加了诸多的代码量,非常不利于后期的调试和代码检查。为了简便,决定利用 Extension 为其增加基于 Block 的事件处理方式,核心代码如下(仅提供了 touchUpInside 事件的处理代码):

public typealias UIControlEventBlock = @convention(swift) (UIControl) -> ()

extension UIControl {
    
    /// 定义 Runtime 时用到的键值。
    fileprivate struct _RawPointers {        
        /// 在控件上按下并抬起
        static let touchUpInside = UnsafeRawPointer(bitPattern: "automatic_touch_up_inside".hashValue)
        /// 其他事件类似声明...
    }
    
    /// 在控件上按下并抬起时的处理代码。
    public var touchUpInsideBlock: UIControlEventBlock? {
        set {
            if let pointer = _RawPointers.touchUpInside {
                self.removeTarget(self, action: #selector(onTouchUpInside), for: .touchUpInside)
                objc_setAssociatedObject(self, pointer, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
                self.addTarget(self, action: #selector(onTouchUpInside), for: .touchUpInside)
            }
        }
        
        get {
            if let pointer = _RawPointers.touchUpInside {
                return  objc_getAssociatedObject(self, pointer) as? UIControlEventBlock
            }
            return nil
        }
    }
    
    /// 在控件上按下并抬起时的处理函数
    @objc private func onTouchUpInside() {
        if let block = self.touchUpInsideBlock {
            block(self)
        }
    }
}

使用时,同样的 touchUpInside 处理就可以被简化为:

ctl.touchUpInsideBlock = { control in
    print("事件的处理代码")
}
上一篇 下一篇

猜你喜欢

热点阅读