22
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

UIButtonにアクションを設定するとき引数も渡す

Last updated at Posted at 2013-08-12

 UIButtonaddTarget: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関数が可変長引数なので、やろうと思えばいくつでも引数を増やせる。と思う。

BlockからSelector(メソッド)を作る - Qiita

Objective-C Runtime Reference - Mac Developer Library

 追記。CocoaPods に登録しました。どうぞ、可愛がってやってください。

woxtu/UIButton-WithObject - GitHub

22
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?