2012年4月2日月曜日

Blocksで既存メソッドを置き換える

BlockからIMPを作り出す関数 imp_implementationWithBlock() を使ったテクニック。面白い。


(以下、引用)

こんなのを用意しておけば
void
replaceMethodWithBlock(Class cls, SEL sel, id (^blockGen)(SEL, IMP))
{
    IMP originalImplementation = NULL;
    Method originalMethod = class_getInstanceMethod(cls, sel);
    if (!originalMethod) {
        [NSException raise:NSInvalidArgumentException format:@"method not found:%s", sel];
    }
    originalImplementation = method_getImplementation(originalMethod);
    id block = blockGen(sel, originalImplementation);
    if (!block) {
        return;
    }
    IMP imp = imp_implementationWithBlock((__bridge void*) block);
    method_setImplementation(originalMethod, imp);
}

こんな感じで簡単に書ける。
replaceMethodWithBlock([NSWindow class], @selector(mouseDown:), 
        // block to generate block for method.
        (id) ^(SEL selector, IMP originalImplimentation) {
            // block for method.
            void (^block)(id, NSEvent*) = ^(id self, NSEvent *theEvent) {
                NSLog(@"[BEFORE] mouseDown:%@", theEvent);
                originalImplimentation(self, selector, theEvent);
                NSLog(@"[AFTER] mouseDown:");
            };
            return block;
       });
上記は NSWindow の mouseDown: 前後にログを書きだすブロックで mouseDown: を置換している。

0 件のコメント:

コメントを投稿