Objective-C で動的にメソッドを追加する

Objective-C でも、Ruby みたいに動的にメソッドを追加することができた。 ということは、Objective-C でもメタプログラミングができるね。

今のところ、セレクタを引数に受け取るメソッドのテストで重宝している。

#import "MyTests.h"
#import <objc/runtime.h>

@implementation MyTests

- (void)testAddDynamicMethod
{
  __block BOOL called = NO;

  // メソッドの本体になるブロック
  // 第1引数は self を受け取る
  void (^testBlock)(id, NSNotification*) = ^(id self, NSNotification *notificateion) {
    called = YES;
  };

  // セレクタを作成
  SEL sel = NSSelectorFromString(@"testMethod");

  // ブロックからメソッドの実装を作成
  IMP imp = imp_implementationWithBlock(testBlock);

  // クラスのメソッドに追加
  class_addMethod([MyViewControllerTests class], sel, imp, "v@:@");

  // @selector には NSSelectorFromString に指定した名前を渡す
  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(testMethod)
                                               name:@"foo"
                                            object:nil];

  NSNotification *n = [NSNotification notificateionWithName:@"foo" object:self];
  [[NSNotificationCenter defaultCenter] postNotofication:n];
  STAssertTrue(called, @"ブロックは呼ばれました");
}

class_addMethod の最後の引数で渡している文字列は、メソッドのシグネチャ文字列。