Swift 4
Здесь является быстрым Использованием решения
class ClosureSleeve {
let closure: () -> ()
init(attachTo: AnyObject, closure: @escaping () -> ()) {
self.closure = closure
objc_setAssociatedObject(attachTo, "[\(arc4random())]", self, .OBJC_ASSOCIATION_RETAIN)
}
@objc func invoke() {
closure()
}
}
extension UIControl {
func addAction(for controlEvents: UIControlEvents = .primaryActionTriggered, action: @escaping () -> ()) {
let sleeve = ClosureSleeve(attachTo: self, closure: action)
addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
}
}
В качестве примера:
button.addAction {
print("button pressed")
}
Мне легко и универсальный для использования крошечного класса помощника:
@interface Handler : NSObject
@end
@implementation Handler {
void (^block)(id);
}
+ (Handler *)create:(void (^)(id))block {
Handler *result = [[Handler alloc] init];
result->block = block;
return result;
}
- (void)call:(id)sender {
block(sender);
}
@end
и использование это как это:
Handler *handler = [Handler create:^(id sender) {
// ... handle the event, using local state captured by the block ...
}];
// store the handler because the target is not retained in addTarget
[handlers addObject:handler];
[button addTarget:handler action:@selector(call:) forControlEvents:UIControlEventTouchUpInside];
Быстрое расширение / основанная на категории реализация, которую я сделал на скорую руку. Используя связанные объекты OBJC не антишаблон. :P
import UIKit
// MARK: UIControl Block based actions
typealias ActionBlock = (UIControl) -> ()
class UIButtonActionDelegate : NSObject {
let actionBlock : ActionBlock
init(actionBlock: ActionBlock) {
self.actionBlock = actionBlock
}
func triggerBlock(control : UIControl) {
actionBlock(control)
}
}
private var actionHandlersKey: UInt8 = 0
extension UIControl {
var actionHandlers: NSMutableArray { // cat is *effectively* a stored property
get {
return associatedObject(self, key: &actionHandlersKey, initialiser: { () -> NSMutableArray in
return NSMutableArray()
})
}
set { associateObject(self, key: &actionHandlersKey, value: newValue) }
}
func addBlockForEvents(events: UIControlEvents, block: ActionBlock) {
let actionDelegate = UIButtonActionDelegate(actionBlock: block)
actionHandlers.addObject(actionDelegate) // So it gets retained
addTarget(actionDelegate, action: #selector(UIButtonActionDelegate.triggerBlock(_:)), forControlEvents: events)
}
}
// MARK: Associated Object wrapper
func associatedObject<ValueType: AnyObject>(
base: AnyObject,
key: UnsafePointer<UInt8>,
initialiser: () -> ValueType)
-> ValueType {
if let associated = objc_getAssociatedObject(base, key)
as? ValueType { return associated }
let associated = initialiser()
objc_setAssociatedObject(base, key, associated,
.OBJC_ASSOCIATION_RETAIN)
return associated
}
func associateObject<ValueType: AnyObject>(
base: AnyObject,
key: UnsafePointer<UInt8>,
value: ValueType) {
objc_setAssociatedObject(base, key, value,
.OBJC_ASSOCIATION_RETAIN)
}