UIButton
へ addTarget:action:forControlEvents:
を送るとき、セレクタの他に引数としてオブジェクトを渡したいときがあるらしいです。動的なメソッド追加を利用すれば再現できそう。
#import <Foundation/Foundation.h>
#import <objc/message.h>
#import <objc/runtime.h>
@interface UIButton (WithObject)
- (void)addTarget:(id)target action:(SEL)action withObject:(id)object forControlEvents:(UIControlEvents)controlEvents;
- (void)removeTarget:(id)target action:(SEL)action withObject:(id)object forControlEvents:(UIControlEvents)controlEvents;
@end
@implementation UIButton (WithObject)
- (void)addTarget:(id)target action:(SEL)action withObject:(id)object forControlEvents:(UIControlEvents)controlEvents {
// 渡されたセレクタとオブジェクトから新しいセレクタを作成
NSString* replaced = [NSStringFromSelector(action) stringByReplacingOccurrencesOfString:@":" withString:@"_"];
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"%@%tu", replaced, [object hash]]);
// 渡されたセレクタとオブジェクトでメッセージを送るだけのメソッドを追加
IMP impl = imp_implementationWithBlock(^(id self_) {
objc_msgSend(self_, action, self, [object copy]);
});
class_replaceMethod([target class], selector, impl, "v@:@");
// 追加したメソッドをターゲットに登録
[self addTarget:target action:selector forControlEvents:controlEvents];
}
- (void)removeTarget:(id)target action:(SEL)action withObject:(id)object forControlEvents:(UIControlEvents)controlEvents {
// 渡されたセレクタとオブジェクトから追加したセレクタを作成
NSString* replaced = [NSStringFromSelector(action) stringByReplacingOccurrencesOfString:@":" withString:@"_"];
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"%@%tu", replaced, [object hash]]);
// 追加したメソッドをターゲットから削除
[self removeTarget:target action:selector forControlEvents:controlEvents];
}
@end
@interface ViewController ()
@property (readwrite, nonatomic, weak) IBOutlet UIButton* effect_button;
@property (readwrite, nonatomic, weak) IBOutlet UIButton* remind_button;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.effect_button addTarget:self action:@selector(call:withMessage:) withObject:@"Amnesia effect!" forControlEvents:UIControlEventTouchUpInside];
[self.remind_button addTarget:self action:@selector(call:withMessage:) withObject:@"Amnesia remind!" forControlEvents:UIControlEventTouchUpInside];
}
- (IBAction)call:(id)sender withMessage:(NSString*)message {
NSLog(@"%@", message);
}
@end
objc_msgSend
関数が可変長引数なので、やろうと思えばいくつでも引数を増やせる。と思う。
追記。CocoaPods に登録しました。どうぞ、可愛がってやってください。