ページ

2009年10月26日月曜日

Safari用独自プラグインを作る(9) - Method Swizzling 補足

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

(前回)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( ) は(多分)不要になる。