【コラム】

ダイナミックObjective-C

4 ターゲット/アクションパラダイム(1) - 動的特性を利用したデザインパターン

    木下誠  [2005/08/31]

    前回は、Objective-Cでの動的なクラスやメソッドの調査を取り上げた。ここまで読んで、次のような感想を持った方もいるだろう。「なるほど、確かにそういうことができることは分かった。だが、動的、動的というが、それが何の役に立つのか?」と。

    プログラミングの手法は、それを積極的に取り入れたフレームワークがあることでその存在が光る。そこで今回は、Cocoaフレームワークから動的なメソッド調査を利用するパターンを紹介しよう。それはGUIにおけるメニューの呼び出しである。

    メニューの呼び出し

    GUIを提供するフレームワークでの、メニューのための仕組みを考えよう。特に、メニューが選択されたときに、どうやってアプリケーション側のメニュー処理メソッドを呼び出すか、というところについて細かく考える。

    メニュー処理というのは、つきつめて言ってしまえば、メニューが選択されたときに、あるオブジェクトのあるメソッドを呼び出すことである。したがって、いちばん簡単な実装方法は、メニューが選択されたときに呼び出すオブジェクトとメソッドを、プログラム中でハードコーディングしてしまうことである。しかしこの方法は、アプリケーションが少し複雑になるとあっと言う間に破綻する。メニューを持つアプリケーションは、次のような問題を解決する必要があるからだ。

    メニュー実行の対象の変更

    あるメニューが行うコマンドは、状況によって変化する。たとえば、カットやコピーといったコマンドは、テキストフィールドが選択されていればテキストのコピーを行うし、ファイルが選択されていればファイルのコピーを行う。場合に応じて、呼び出すオブジェクトとメソッドを変更する必要がある。

    有効/無効の切り替え

    任意の状況で、あるメニューが使用可能かどうか切り替える必要がある。たとえば、ペーストが実行できないオブジェクトが選択されていたら、そのためのメニューは無効化しなくてはいけない。

    変更の容易さ

    メニューに表示される文字は、アプリケーションの開発途上で、頻繁に変更することになるだろう。これを簡単に行うことができた方がいい。特に、再コンパイルなしで変更できたらありがたい。

    これらは、すべてのGUIを持つアプリケーションにおいて共通する問題だろう。様々なフレームワークがこれらのために色々な解決策を持っている。今回から紹介するCocoaによる解決方法は、動的な型付けとメソッドの調査を利用するものである。その結果、非常に単純で直接的なものになっていることに気づくだろう。

    nibファイル

    メニューの説明の前に、nibファイルと呼ばれるファイルを紹介しよう。Cocoaでは、メニューを含むGUIは、nibファイルによって定義される。このファイルは、Interface Builderという専用のアプリケーションで作成される。

    Interface Builderが、他の開発環境のGUIデザイナと決定的に違うのは、Objective-Cのソースコードを作成しないということだ。GUIのデザインが書かれたnibファイルには、生のソースコードは含まれない。したがってこれを変更しても、アプリケーションをコンパイルする必要はないということになる。実際には、このファイルはGUIのオブジェクトをエンコードしたものを含む。

    この連載の観点からみれば、nibファイルに関して1つ面白いことがある。nibファイルに書かれるクラスやメソッドの存在は、実はアプリケーションをビルドする時点では保証されない。実行時にnibファイルを読み込んだ時点で、初めてランタイム上にそのクラスやメソッドがあるか評価される。ここが、ポイントとなるわけだ。

    ターゲットとアクション

    では、nibファイルでのメニューの定義方法を詳しく見ていこう。メニューは、Interface Builderを使い、ドラッグアンドドロップで項目を追加して作っていく。

    今回注目するのは、メニュー選択時の動作の設定方法である。Cocoaでは、ここでターゲットとアクションという考え方を使う。ターゲットとはメニューの処理を行う対象、アクションは実際に行う処理の内容である。つまり、ターゲットとはオブジェクト、アクションとはセレクタ(メソッドの名前)ということになる。

    これらの設定について、Interface Builderでは非常に直感的に行うことができる。まず、ターゲットとなるオブジェクトにアクションをいくつか追加し、インスタンスを作る。そして、メニューからドラッグして接続のための線を引っ張りだし、ターゲットを指定し、アクションを選択する。

    「New」メニュー項目から線を出して、ターゲットとなるオブジェクトを選択し、そのオブジェクトの持つアクションを選択する

    ここでポイントとして押さえておきたいことは、次の2つである。

    まず、オブジェクトがターゲットとなるために必要な条件は何か。実は、何も無い。特定のクラスを継承したり、特定のメソッドを実装したりする必要はない。Objective-Cのオブジェクトでさえあれば、メニューのターゲットとなる。

    そして、もう1つのポイントはアクションの定義方法である。アクションはセレクタ、つまりメソッドの名前で指定する。Interface Builderは、クラスの実装ファイルとは独立して動かすことができるので、実はまだ存在しないメソッドも指定することができる。

    ここで、実装しているかどうか分からないメソッドを呼び出すように設定することに、不安を感じるだろうか。実際の動作時には、respondsToSelector:を用いてメソッドの実装の有無を調べることになるので、実行には問題がない。むしろここで大事なのは、メソッドの実装をしているか、していないかがそのオブジェクトの特性になっている、ということである。メソッドを実装しない、ということも、立派な特性の1つである。Cocoaはこれを利用しているわけだ。

    ここまでで、メニューの定義ができた。次回は、実際のメニューの動作を詳しく見てみよう。

    新着記事

    特設サイトの情報

      人気記事

      一覧

        イチオシ記事

        新着記事

        特別企画

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