(前回)Cocoaの日々: Safari用独自プラグインを作る(8) - コンテキストメニューにメニュー追加
前回の swizzleMethodForClass( ) の補足。
-(void)swizzleMethodForClass:(Class)cls orginalSelector:(SEL)org_sel alternativeSelector:(SEL)alt_sel { Method org_method = class_getInstanceMethod(cls, org_sel); class_addMethod(cls, alt_sel, class_getMethodImplementation([self class], alt_sel), method_getTypeEncoding(org_method)); Method alt_method = class_getInstanceMethod(cls, alt_sel); method_exchangeImplementations(org_method, alt_method);
処理をイメージ化してみた。こんな感じ。
1. まず class_addMethod()を使い、BrowserView へ代替メソッド(_sx_webView:...)を追加する。
2. 次に method_exchangeImplementations() を使い、メソッドの実装を交換する。
3. webView:.. メッセージが投げられると、代替実装が実行される。
class_addMethod( ) の第3引数は、代替メソッドの IMP(実態は関数ポインタ) を渡す必要がある。このために [self class]、すなわち SXSafariContextMenuSwizzler クラスと、代替メソッドのセレクタ(_sx_webView:..)を使い IMP を取得している。
class_getMethodImplementation([self class], alt_sel),
また引数の型情報を得るのに元メソッドの情報を利用している。
method_getTypeEncoding(org_method));
- - - -
SXSafariContextMenuSwizzler を BrowserWebViewのサブクラスにしたり、代替メソッドを BrowserWebView のカテゴリとすれば method_exhcangeImplementations( ) だけで良さそう。class_addMethod( ) は(多分)不要になる。