【コラム】

ダイナミックObjective-C

7 Objective-Cと様々な言語のブリッジ - PyObjC、RubyCocoa……

    木下誠  [2005/09/21]

    前回は、Objective-CとJavaの間でのブリッジを、Cocoaのターゲット/アクションパラダイムに着目して紹介したが、他の言語からもObjective-Cへのブリッジが存在する。特に、スクリプティング言語とのブリッジは、お互いに動的な特性が似ているので、実現しやすいようだ。今回は、それらを考察してみたい。

    PyObjCとRubyCocoa

    PyObjCはPythonと、RubyCocoaはRubyとの間で、Objective-Cへのブリッジを実現する。どちらのライブラリも、Cocoaを含むObjective-Cベースのフレームワークにアクセスすることができ、使い慣れた言語を使ってアプリケーションを作ることができる。また、XcodeやInterface Builderといった、Mac OS Xとの開発環境とも統合されており、完成度は高い。

    では前回に引き続き、これらのライブラリでのセレクタの扱いを見てみよう。Python、Rubyともに、メソッドをオブジェクトとして扱う機構は持っているが、これらはObjective-Cのセレクタと直接交換はできない。そこで、文字列を使ってセレクタの代用をしている。

    たとえば、PyObjCでは、次のようなソースコードで、他のアプリケーション起動の通知を受け取ることができる。

    class PyObjcTestAppDelegate(NibClassBuilder.AutoBaseClass):
        # 起動の通知を受け取るメソッド
        def willLaunchApplication_(self, notification):
            print "An application is launched"
        
        def awakeFromNib(self):
            # NSWorkspaceのインスタンスを取得
            workspace = NSWorkspace.sharedWorkspace()
            notificationCenter = workspace.notificationCenter()
            # 通知を受け取るために、インスタンスとメソッドを登録
            notificationCenter.addObserver_selector_name_object_(
                    self, 
                    "willLaunchApplication:", 
                    NSWorkspaceWillLaunchApplicationNotification, 
                    None)

    NSWorkspaceというクラスを使い起動通知の受け取り処理を行っている。注目してほしいのは最後の処理である、addObserver_selector_name_objectというメソッドだ。このメソッドは通知受け取りの登録をするもので、第1引数にオブジェクトを、第2引数では呼び出されるメソッドの名前を文字列で指定している。

    上のソースコードにあるように、PyObjCでは、指定するメソッド名はObjective-Cスタイルになっている。つまり、実際のCocoaへの登録、および通知の受け取りは、Objective-C空間で行われることになる。通知を受け取った後は、Objective-Cメソッド名をPythonスタイルに変換し、そのPython空間のメソッドを呼び出すことになる。

    つまりここでも、文字列からのメソッド呼び出し機構が重要な役割を果たしている訳だ。

    C++ブリッジは可能か?

    では、C++ではどうだろう?C++で、このようなObjective-Cブリッジを作ることはできるだろうか。結論から言ってしまえば、非常に難しい。いろいろな問題があるが、このターゲット/アクションの実装に限っても、任意のメソッドを変数として与えて実行するという機能がないため、代替物がないからだ。

    C++でこの種の機能に一番近いものは、メンバ関数ポインタとなるだろうか。だがメンバ関数ポインタは、実装そのものを指すもので、そのクラスやメソッドに関する情報は含まれない。これでは、実装の有無をチェックしたり、セレクタのように異なるクラスに対して適用するといったことは、無理である。

    どうしてもC++で実装するならば、メンバ関数ポインタとメンバ関数名のテーブルを作り、実行時に探索して呼び出すことになる。これは、動的な言語のランタイムが行っていることを、もう一度作り直すことと同じになるだろう。

    Objective-Cのメッセージ送信

    ターゲット/アクションパライダイムを切り口として、様々な言語とObjective-Cとのブリッジを紹介してみたが、これで明らかになったのは、Cocoa + Objective-Cで求められていることは、メソッドを、メソッドの実体と切り離した状態で記述し、それを任意のオブジェクトに対して適用することだ。

    Objective-Cではこのことを、メッセージ送信と呼ぶ。「メッセージ送信」という言葉は様々な文脈で使われるが、Objective-Cではこのような意味で使われる。メッセージの実体となるのはセレクタだ。このメッセージ送信の中に、Objective-Cの動的特性の醍醐味がある。後日稿を改めてメッセージング機構の大解剖を行い詳しく解説することになるだろう。

    新着記事

    特設サイトの情報

      人気記事

      一覧

        イチオシ記事

        新着記事

        特別企画

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