|
/// Block for addTarget |
|
extension UIControl { |
|
|
|
public typealias UIControlActionBlock = (_ sender: UIControl) -> Void |
|
|
|
public class UIControlClosureWrapper { |
|
let owner: UIControl |
|
let actionBlock: UIControlActionBlock |
|
let event: UIControlEvents |
|
|
|
init(owner: UIControl, |
|
block: @escaping UIControlActionBlock, |
|
event: UIControlEvents) { |
|
self.owner = owner |
|
self.actionBlock = block |
|
self.event = event |
|
objc_setAssociatedObject(owner, |
|
&ActionBlockKey, |
|
self, |
|
.OBJC_ASSOCIATION_RETAIN_NONATOMIC) |
|
} |
|
|
|
@objc func fire() { |
|
actionBlock(owner) |
|
} |
|
|
|
@objc func fireOnce() { |
|
actionBlock(owner) |
|
owner.removeActionBlock() |
|
} |
|
} |
|
|
|
@discardableResult |
|
public func addActionBlock(fireOnce: Bool = false, |
|
for event: UIControlEvents = .touchUpInside, |
|
_ block: @escaping UIControlActionBlock) -> UIControl.UIControlClosureWrapper { |
|
let w = UIControlClosureWrapper(owner: self, block: block, event: event) |
|
let selector = fireOnce ? #selector(UIControlClosureWrapper.fireOnce) : #selector(UIControlClosureWrapper.fire) |
|
addTarget(w, action: selector, for: event) |
|
return w |
|
} |
|
|
|
public func removeActionBlock(wrapper: UIControl.UIControlClosureWrapper? = nil) { |
|
var w: UIControl.UIControlClosureWrapper |
|
if wrapper == nil { |
|
guard let associatedWrapper = objc_getAssociatedObject(self, &ActionBlockKey) as? UIControlClosureWrapper else { print("⚠️ UIControl -> removeActionBlock -> Can't remove action block."); return } |
|
w = associatedWrapper |
|
} else { |
|
w = wrapper! |
|
} |
|
|
|
self.removeTarget(w, action: #selector(UIControlClosureWrapper.fire), for: w.event) |
|
self.removeTarget(w, action: #selector(UIControlClosureWrapper.fireOnce), for: w.event) |
|
|
|
objc_removeAssociatedObjects(w) |
|
} |
|
} |
|
|
|
|
|
|
|
// or |
|
|
|
|
|
|
|
// MARK: - Tappabale |
|
private var kButtonBlockAssociationKey: UInt8 = 0 |
|
public extension UIButton { |
|
class ClosureWrapper { |
|
var closure: VoidCompletion? |
|
|
|
init(_ closure: VoidCompletion?) { |
|
self.closure = closure |
|
} |
|
} |
|
|
|
internal var tapButtonBlock: VoidCompletion? { |
|
get { |
|
if let cw = objc_getAssociatedObject(self, |
|
&kButtonBlockAssociationKey) as? ClosureWrapper { |
|
return cw.closure |
|
} |
|
return nil |
|
} |
|
set(newValue) { |
|
objc_setAssociatedObject(self, |
|
&kButtonBlockAssociationKey, |
|
ClosureWrapper(newValue), |
|
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) |
|
} |
|
} |
|
|
|
/** Links UIButton tap (TouchUpInside) event to a block. |
|
|
|
Example Usage: |
|
|
|
``` |
|
button.tap { |
|
// do something |
|
} |
|
``` |
|
|
|
Or |
|
``` |
|
button.tap(doSomething) |
|
|
|
// later |
|
func doSomething() { |
|
// ... |
|
} |
|
``` |
|
|
|
- Returns: Itself for chaining purposes |
|
|
|
*/ |
|
@discardableResult |
|
func didTap(_ block:@escaping () -> Void) -> UIButton { |
|
addTarget(self, action: #selector(UIButton.tapped), for: .touchUpInside) |
|
tapButtonBlock = block |
|
return self |
|
} |
|
|
|
/** */ |
|
@objc func tapped() { |
|
tapButtonBlock?() |
|
} |
|
} |