在我的项目中,我将错误提示页面的设置放在了一个类当中,方便其他页面的调用,但是这个页面有个用于重新加载的Button,我如何在其他的类为这个Button添加target呢?我想到了block的方式。接下来让我们看看如何实现。
在实现之前我们先了解一个两个方法
objc_setAssociatedObject(_:_:_:_:) 和objc_getAssociatedObject(_:_:)
这两个是runtime函数。对相关联的两个方法。
objc_setAssociatedObject(_:_:_:_:) 有四个参数
-
object表示关联者,是一个对象,这里是UIButton(The source object for the association) -
key被关联者的索引key,所以他是唯一的(The key for the association) -
value被关联者,这里就是我们的block,如果这里传进来的是nil,那就表示断开关联(The value to associate with the key key for object. Pass nil to clear an existing association) -
policy:关联策略。有五种关联策略。
OBJC_ASSOCIATION_ASSIGN等价于@property(assign)
OBJC_ASSOCIATION_RETAIN_NONATOMIC等价于@property(strong, nonatomic)
OBJC_ASSOCIATION_COPY_NONATOMIC等价于@property(copy, nonatomic)
OBJC_ASSOCIATION_RETAIN等价于@property(strong,atomic)
OBJC_ASSOCIATION_COPY等价于@property(copy, atomic)
objc_getAssociatedObject(_:_:) 就顾名思义了,就是获取被关联者。它有两个参数。
-
object和set方法一样,表示关联者(The source object for the association) -
key被关联者的key(The key for the association)
我们所要做的就是将我们要传递的block关联到UIButton上去。
OK,准备完毕,接下来就是Coding的时候了。
首先,我们先来设置被关联者的key
var actionBlockKey: UInt8 = 0
声明我们的block,这个block就是我们要传进来的方法。
typealias BlockButtonActionBlock = (_ sender: UIButton) -> Void
接下来我们定义一个action的方法
class ActionBlockWrapper: NSObject {
var block: BlockButtonActionBlock
init(block: @escaping BlockButtonActionBlock) {
self.block = block
}
}
接下来就是关键的步骤,为UIButton添加扩展:
extension UIButton {
func block_setAction(block: @escaping BlockButtonActionBlock) {
objc_setAssociatedObject(self, &actionBlockKey, ActionBlockWrapper(block: block), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
addTarget(self, action: #selector(UIButton.block_handleAction(sender:)), for: .touchUpInside)
}
func block_handleAction(sender: UIButton) {
if let wrapper = objc_getAssociatedObject(self, &actionBlockKey) as? ActionBlockWrapper {
wrapper.block(sender)
}
}
}
这里我们将我们传入的方法绑定到了UIButton的target上,就实现了,运用block为UIButton绑定target。我们在使用的时候,就不需要写addTarget方法,直接一个block搞定。
myButton.block_setAction { sender in
}