【コラム】

ダイナミックObjective-C

47 AspectCocoa (5) - インプットマネージャとの連携

    木下誠  [2006/08/23]

    先日のWWDCで発表されたObjective-C 2.0だが、現在公開されている情報をレポートにまとめたので、興味のある方はこちらを参照してほしい

    インプットマネージャとAspectCocoaの連携

    AspectCocoaの特徴は、アスペクトの織り込みを行う対象になるソフトウェアのソースコードが必要ないことだ。これは、メソッドの置換やフォワーディングといった、Objective-Cの動的な特性を利用してアスペクト指向を行っているからである。

    さらに、Objective-Cでは、インプットマネージャを利用することで、既存のコンパイル済みのソフトウェアに侵入することができる。これは、本連載の第41回で説明した通りだ。

    この2つを組み合わせると、次のような結論になる。「AspectCocoaとObjective-Cを使えば、コンパイル済みのアプリケーションに対しても、アスペクト指向を行える」。

    これは、大変魅力的な結論だ。既存のアプリケーションすべてが、アスペクト指向の対象になる。もともとアスペクト指向とは、もとのアプリケーションのコードを変更することなく、横断的な機能を追加することを目的としている考え方だ。ならば、もとのコードは必要ないとなるのは、ある意味当然ではないか?

    まずは、簡単な実験を行ってみよう。まず、アスペクトの織り込みを行う、ソフトウェアモジュールを作る。そのために、Xcodeを使って、「Cocoa Bundle」を作成する。そして、loadメソッドの中で、前回説明したように、ポイントカットの設定を行う。例として、画面のビューを表すNSViewクラスの、初期化を行うinitWithFrame:メソッドに、ポイントカットを設定してみた。

    次に、このモジュールをインプットマネージャから侵入させる。~/Library/InputManagersにフォルダを作り、さきほど作ったモジュールと、Infoファイルを置けばいい。詳しい手順は、第41回を参照してほしい。

    これで、すべてのアプリケーションに対して、ロギングが行える。この場合、ログは標準出力に表示されるので、コンソールアプリケーションを使うことで確認できる。

    次の図は、Safariを起動したときのログの様子だ。様々なビューの初期化が行われていることが分かる。注目すべきところは、標準のCocoaのクラスだけではなく、プライベートなクラスや、Safariが独自に作成したクラスの初期化も分かることだ。既存のアプリケーションの動作や構成を探るのに、圧倒的な力を発揮するだろう。

    実用的な応用

    もう少し、実用的な応用も試してみよう。同じく、Safariをターゲットとする。Safariを使って、Webページをブラウズするときに、発生したすべてのHTTPリクエストとレスポンスを表示させてみよう。

    Safariは、Webページのレンダリングに、Objective-Cで書かれたWeb Kitを使っている。Web Kitでは、HTTPリクエストのレスポンスが確定すると、webView:didCommitLoadForFrame:というメソッドを使って、アプリケーションに通知することになっている。このメソッドに、ポイントカットをしかけてみよう。

    さらに、リクエストとレスポンスの表示は、ログとしてテキストで出力するのではなく、新たにウィンドウを一枚作り、そちらで表示しよう。アスペクト指向のためのモジュールは、普通のCocoaソフトウェアなので、Cocoaの機能はすべて使える。

    実装

    モジュールは、2つのクラスで構成することにする。1つは、アスペクトの設定をしたり、ウィンドウへの表示を行うコントロールクラス。もう1つは、織り込み先から呼び出されるアドバイスオブジェクトだ。

    アドバイスオブジェクトのソースを紹介しよう。AspectCocoaでは、アドバイスのためのルートクラスは存在しない。単に、after:やbefore:といったメソッドを実装すれば、それがアドバイスになる。ここでは、HSAdviceというクラスを作り、after:メソッドを実装してみた。

    @interface HSAdvice : NSObject
    {
    }

    - (void)after:(ACInvocation*)invocation;

    @end

    @implementation HSAdvice

    - (void)after:(ACInvocation*)invocation
    {
        // Webビューを取得する
        WebView* webView;
        [invocation getArgument:&webView atIndex:2];
        if (!webView) {
            return;
        }

        // リクエストとレスポンスを取得する
        NSURLRequest*    request;
        NSURLResponse* response;
        request = [[[webView mainFrame] dataSource] request];
        response = [[[webView mainFrame] dataSource] response];

        // コントローラに、リクエストとレスポンスを追加する
        [[HSController sharedController] addRequest:request andResponse:response];
    }

    @end

    after:メソッドは、ACInvocationというクラスを引数にとる。これは、NSInvocationと似た働きをするクラスで、ポイントカットのメソッドの、返り値や引数を取得することができる。

    この実装では、まず、引数に渡されるWebViewオブジェクトを取得している。そこから、HTTPリクエストとレスポンスを取り出すことができるのだ。そして、それらをコントロールクラスに渡し、ウィンドウに表示させている。

    こうしてでき上がったのが、HTTPリクエストとレスポンスを覗く、「HTTP Sneaker」である。Safariでブラウズすると、すべてのリクエストとレスポンスを表示していく。

    このように、既存のアプリケーションに機能を付け加えるという点で、アスペクト指向の特徴を活用できる。AspectCocoaとObjective-Cの組み合わせの場合、アスペクト指向は将来ブレークする技術ではない。いま、使える技術である。

    今回の成果物(HTTPSneaker.zip)

    新着記事

    特設サイトの情報

      求人情報

      人気記事

      一覧

      イチオシ記事

      新着記事

      特別企画

      転職ノウハウ

      あなたの仕事適性診断

      4つの診断で、自分の適性を見つめなおそう!

      Heroes File ~挑戦者たち~

      働くこと・挑戦し続けることへの思いを綴ったインタビュー

      はじめての転職診断

      あなたにピッタリのアドバイスを読むことができます。

      転職Q&A

      転職に必要な情報が収集できます

      スカウト転職する

      企業からアプローチのメッセージが届きます。

      マイナビニュースマガジン