class_replaceMethod (Objective-C 2.0)

Objective-C 2.0で(instance)methodを書き換えたい.
そんな時は,Objective-CのRuntime関数をいろいろ使えばできます.
Objective-C 2.0なので,当然iPhoneでも動きます.

method書き換えには,class_replaceMethodを使います.

@interface HogeA : NSObject{
}
@end

@implementation HogeA
-(void)print{
    NSLog(@"Hoge A!");
}
@end

@interface HogeB : NSObject{
}
@end

@implementation HogeB
-(void)print{
    NSLog(@"Hoge B!");
}
@end

というクラス2個があるとして

    //#import <objc/runtime.h>が必要

    HogeA*   hogeA = [[HogeA alloc]init]; //これは別に必要なし.imp(hogeA, selector);用
    SEL  selector = @selector(print);

    IMP imp = class_getMethodImplementation([HogeA class], selector);
    Method method = class_getInstanceMethod([HogeA class], selector);
    struct objc_method_description *desc = method_getDescription(method);
    char *types = desc->types;

    HogeB*   hogeB = [[HogeB alloc]init];
    [hogeB print];

    class_replaceMethod([HogeB class], selector, imp, types);

    [hogeB print];

    [hogeA release];
    [hogeB release];

こういうコードを実行すると,[hogeB print];[hogeB print];と実行しているのに

Hoge B!
Hoge A!

とprintされます.
class_replaceMethodでHogeBのprintをHogeAのprintに置き換えています.
その前の段階で,class_replaceMethodに必要なHogeAのIMPとMethodからtypesを取得しております.

MethodとかIMPの詳細については,ダイナミックObjective-Cが詳しい.
この辺の話は本にも載るのだろうか.

いろいろHackに使える(はずな)のでお試しあれ.

ちなみに,この辺のRuntime関数をばりばり使えば,Objective-C(の[ ])を使わないでCocoaTouchレイヤーが叩けるはず.いじでもC++でやる人等は要チェックです.
たとえば,上記例だと,IMP取得後に,imp(hogeA, selector);を実行すればHogeA :: printが実行できます.

Leave a Reply