2008年6月26日木曜日

メソッドを後から入れ替える.

こんな感じ.
#import <objc/objc-runtime.h>
IMP swapIMPs(SEL selector_from, Class class_from, SEL selector_to, Class class_to)
{
Method method_from, method_to;
IMP IMP_from, IMP_to;

method_from = class_getInstanceMethod(class_from, selector_from);
if(method_from == NULL)
return NULL;
IMP_from = method_from->method_imp;

method_to = class_getInstanceMethod(class_to, selector_to);
if(method_to == NULL)
return NULL;
IMP_to = method_to->method_imp;

method_from->method_imp = IMP_to;
return IMP_to;
}
("#import <objc/objc-runtime.h>"がないとコンパイルがとおらない.)


でこいつができるとカテゴリを使って後からメソッドの動作を書き換えることが出来る.
たとえばあるNSViewのカスタムクラスをさらにあとから(例えばPluginで)付け足す形で入れ替えられる.
その中で以下のようにして呼び出す.(ここではvalidateMenuItemを入れ替えてみる)
static IMP old_IMP= NULL;
old_IMP= swapIMPs(@selector(validateMenuItem:), [self class], @selector(new_validateMenuItem:), [self class]);


このときnew_validateMenuItem:は例えば以下のようにすると既存の実装と同居できることになる.
- (BOOL) new_validateMenuItem:(id )menuItem
{
SEL anAction = [menuItem action];
if(anAction == @selector(hoge:)){
return YES;
}
return validateMenuItem_IMP(self, _cmd, menuItem);
}


ただし10.5では"method_imp"はdeprecatedだそうです.そのうち使えなくなるコードでしょう.
参考:
GPG Mail http://www.sente.ch/software/GPGMail/English.lproj/GPGMail.html

0 件のコメント: