UIControl-多个targets-多个actions
UIControl添加事件
最常见的开发中给按钮添加事件, 我们怎么写?
button.addTarget(self, action: #selector(buttonAction1(_:)), for: .touchUpInside)
相当熟练了哈, 但是要注意给同一个按钮添加多个事件, 或者修改点击事件的问题,
多targets-多actions
addTarget方法文档这么写的:(会有多个targets, 多个actions)
// add target/action for particular event. you can call this multiple times and you can specify multiple target/actions for a particular event.
// passing in nil as the target goes up the responder chain. The action may optionally include the sender and the event in that order
// the action cannot be NULL. Note that the target is not retained.
open func addTarget(_ target: Any?, action: Selector, for controlEvents: UIControl.Event)
测验一下, 可以复制粘贴到你的项目中, 执行一下如下代码(自己创建button):
print("++++++++++++++++++++1")
print(button.actions(forTarget: self, forControlEvent: .touchUpInside))
button.addTarget(self, action: #selector(buttonAction1(_:)), for: .touchUpInside)
print("++++++++++++++++++++2")
print(button.actions(forTarget: self, forControlEvent: .touchUpInside))
button.addTarget(self, action: #selector(buttonAction2(_:)), for: .touchUpInside)
button.addTarget(self, action: #selector(buttonAction3(_:)), for: .touchUpInside)
button.addTarget(self, action: #selector(buttonAction4(_:)), for: .touchUpInside)
print("++++++++++++++++++++3")
print(button.actions(forTarget: self, forControlEvent: .touchUpInside))
++++++++++++++++++++1
nil
++++++++++++++++++++2
Optional(["buttonAction1:"])
++++++++++++++++++++3
Optional(["buttonAction1:", "buttonAction2:", "buttonAction3:", "buttonAction4:"])
++++++++++++++++++++1
UIControl添加事件的优化方法
block
第一个思路, 我改用其他方式给button绑定事件, 比如block, 用起来还更优雅, 这里不得不提到一个大家可能已经在用的分类
extension UIControl {
static let cmButtonAssociatedkey = UnsafeRawPointer.init(bitPattern: "cmButtonAssociatedkey".hashValue)!
func addAction(for controlEvents: UIControl.Event = .touchUpInside, action: @escaping (UIButton) -> Void) {
objc_setAssociatedObject(self, UIButton.cmButtonAssociatedkey, action, .OBJC_ASSOCIATION_COPY_NONATOMIC)
self.addTarget(self, action: #selector(cmButtonClick), for: controlEvents)
}
@objc func cmButtonClick() {
if let action = objc_getAssociatedObject(self, UIButton.cmButtonAssociatedkey) as? (UIButton) -> Void {
action(self)
}
}
}
利用objc_setAssociatedObject 和objc_getAssociatedObject动态添加一个属性, 设置时传入block, 点击时会取出block执行, 很方便
button.addAction(for: .touchUpInside) { [weak self] button in
// do
}
它可以保证你设置的action覆盖掉上一个action, 你在开发中, 哪怕给按钮加十七八个方法, 也只会有最后一个生效
remove - add 事件
另一个方法, 既然你添加的时候会添加多个, 那我把你移除不就好了吗?
apple支持我们自己操作target和action, 点进addtarget的文档, 有好几个方法, 我们只需要看两个:
// get info about target & actions. this makes it possible to enumerate all target/actions by checking for each event kind
open var allTargets: Set<AnyHashable> { get } // set may include NSNull to indicate at least one nil target
// remove the target/action for a set of events. pass in NULL for the action to remove all actions for that target
open func removeTarget(_ target: Any?, action: Selector?, for controlEvents: UIControl.Event)
- 拿到N个targets
- 移除actions(看第二个移除方法, 不传action, 表示移除所有的actions)
这里面具体的要移除控件所有的target还是指定target, 是所有的actions还是指定的action, 自己根据需求去判断, 假设我们移除所有的targets和actions:
for target in button.allTargets {
// target也可以自己传过来, action我们传nil表示所有事件, 后面的touchUpInside自己看之前添加的时候传的啥
button.removeTarget(target, action: nil, for: .touchUpInside)
}
试试看, 上面的代码最后一个addTarget前, 我们来移除他的所有的actions
print("++++++++++++++++++++1")
print(button.actions(forTarget: self, forControlEvent: .touchUpInside))
button.addTarget(self, action: #selector(buttonAction1(_:)), for: .touchUpInside)
print("++++++++++++++++++++2")
print(button.actions(forTarget: self, forControlEvent: .touchUpInside))
button.addTarget(self, action: #selector(buttonAction2(_:)), for: .touchUpInside)
button.addTarget(self, action: #selector(buttonAction3(_:)), for: .touchUpInside)
for target in button.allTargets {
button.removeTarget(target, action: nil, for: .touchUpInside)
}
button.addTarget(self, action: #selector(buttonAction4(_:)), for: .touchUpInside)
print("++++++++++++++++++++3")
print(button.actions(forTarget: self, forControlEvent: .touchUpInside))
++++++++++++++++++++1
nil
++++++++++++++++++++2
Optional(["buttonAction1:"])
++++++++++++++++++++3
Optional(["buttonAction4:"])
ok, 搞定
总结
如果遇到action前后变化的时候, 要留意是保留多个actions还是覆盖掉上一个.
方便的时候, 你可以用block的方式执行事件, 这样便于书写和阅读.
你问我为什么会选择用selector, 这里我补充一个, 平常遇到多个事件摆在一起, 习惯创建一个模型数组, 事件用string表示, 这样执行代码可以用:
// OC
/// 执行自定义方法
- (void)performSelfFuncWithString:(NSString *)funcString object:(id)obj {
if (funcString.length == 0) {
return;
}
if ([self respondsToSelector:NSSelectorFromString(funcString)]) {
SEL selector = NSSelectorFromString(funcString);
IMP imp = [self methodForSelector:selector];
// 第一个id表示执行对象, SEL是方法选择器, 第二个id是参数, 可以为空, 直接传nil
void (*func)(id, SEL, id) = (void *)imp;
func(self, selector, obj);
}
}
绑定好之后, 我传值, 调用, 都非常的方便, 主要还是养成习惯了

浙公网安备 33010602011771号