SSブログ

Mac用USBデバイス-93 Cocoaバインディング [Mac用USBデバイス工作]

EZ-USBを動作させるためには、デスクリプタを記述しないといけないが、記述量はかなり多いということがわかった。そこで自動生成するようなUSB Desimpというソフトを作ることにした。ところが、これはUI(ユーザインターフェイス)リッチなアプリになる。僕はいままで数値計算用のソフトばかり書いてきたのでUIはなおざりにしてきた。

先日のSpaghettiMazeMakerでは「詳細設定パネル」でCocoaバインディングを使った。メインウィンドウが切り替わったときに、そのパネルに反映されるようにするのをターゲット/アクションで書こうとするとかなり大変だけど(コントローラ側はメインウィンドウが切り替わった通知をもらって、パネル側はFirst Responderへのアクションとして)、Cocoaバインディングを使えばInterface Builderでの設定だけでできてしまう。めちゃめちゃ簡単だということがよくわかった。

その伝で今回も行こう。詳細設定パネルぐらい簡単になればいいんだけど。まず、Cocoaバインディングの技術的な基礎について。

5.1  Cocoaバインディング

Cocoaバインディングはガイドのアップルによる日本語訳もある。ただし日本語訳のレビジョンは古いままでフォローされていない。

Cocoaバインディングとはプログラム内部の変数やオブジェクトと、それをユーザに見せて操作させるためにウィンドウの内部などに表示されるオブジェクトとの同期を簡単にとるためのメカニズムで、Mac OS X10.3から導入された。

アプリをMVC(Model-View-Controller)の形にしたとき、ControllerはModelとViewを結びつけて値などの受け渡しをするための部分であって、Controllerの記述は同じような退屈なコードを何度も書かないといけなくて面倒な上に、アプリを書いているとまっさきにぐちゃぐちゃのスパゲティになる部分である。

CocoaバインディングはこのControllerを汎用のオブジェクトとして提供して実質的にControllerの記述が不要になるような機構である。Cocoaバインディングの設定はすべてInterface Builder上で行えて、コードを書く必要はかなり軽減される。あまり複雑なことをしなければまったくコードを書かずにできる。

Cocoaバインディングは
  • キー値バインディング(Key-Value Binding)
  • キー値コーディング(Key-Value Coding、Guide日本語訳
  • キー値監視(Key-Value Observing、Guide日本語訳
と言うメカニズムを使って実現されている。これらをInterface Builder上でできるようにするためにいくつかの工夫がなされている。

5.1.1  Interface Bulderとリソースファイル

Mac OS Xの開発環境(IDE)はNeXTStepから引き継いだXcode(Project Builder)とInterface Builderでできている。Xcodeがプロジェクト管理をしてGUIをInterface Builderで作って、というスタイルはNeXTStepの時代にはIDEの代表格としてパクリのもとになった。

他のエピゴーネンとの最も大きな違いは、Interface Builderがコンパイラやリンカの入力となるようなコードをいっさい吐かないしまた逆に、ただ設定だけをまとめたファイルを作るだけでもない、ということ。

これは、Cocoaオブジェクトをその関連性(参照の繋がり)も含めて(オブジェクトグラフ)ファイルに保存して読み出すCocoa/Objective-CのArchiveという機能を使っていて、コンパイルされるコードとは独立に設定できるからである。このオブジェクトグラフのファイルをリソースと呼ぶ。Interface Builderが作るリソースであるxibファイルはオブジェクトグラフがXMLの形式で書かれていて、オブジェクトがクラス名や保持している別のオブジェクトの参照番号などが並んでいるのを読むことができる。XMLファイルはアプリケーションバンドルの中にコピーされるとき、実行形式のnibファイルに変換される。

このおかげでUIの単体テストができるし、ソースのない実行形式のアプリであっても、例えば英語で表示されているアプリを日本語で表示させるような改造を簡単に行うことができる(というのは昔の話。今のInterface Builderはnibファイルが編集できなくなった)。ただし、ひとつのリソースファイルに含めることのできるオブジェクトグラフには制限がある。リソースに含まれていない外部オブジェクトへの参照は「File's Owner」というただひとつに限られる。リソース上の「File's Owner」はそのリソースが実行時にロードされたときに動的に決定される。

さらにリソースにはメソッド呼び出しも記述できる。リソースに含めることのできるメソッドには制限がある(基本は、id型の引数をひとつだけとって値を返さないシグネチャのメソッドのみ)が、実行コードがまったくなくても動作するアプリが作れるのはこのおかげである。実際にXcodeでリソースだけのアプリを作ってビルドするとNSApplicationMain()を呼ぶ1行だけが書いてあるmain.mをコンパイルした後は、リソースをどう書き換えてもgccは起動されない。xibファイルにはメソッドが文字列の形でそのまま保持されている。

もちろん、リソースに保存されたメソッド呼び出しの実際の動作の記述はリソースにはなく、ライブラリやソースをコンパイルしたコード上にある。なのにリソースにメソッド呼び出しを含めることができるようにするためには、普通に考えれば例えばダイナミックリンクの機構を使ってコードがロードされたときにシンボルを解決する、と言う方法を思いつく。多くのUI作成ツールはそういう方法を使っている。

Interface BuilderはCocoa/Objective-Cらしく、メソッドの実行時バインドを使ってそれを実現している。そのためInterface Builderで設定されたメソッド呼び出しはコンパイラやリンカを経由することがなく、しかしコードのメソッド呼び出しとまったく同じ機構(実際のメソッド解決はランタイムが行う)でメソッドが呼び出されることになる。これはシンプルで美しく、Xcode本体とInterface Builderの役割分担がはっきりとしたCocoa/Objective-Cならではの方法と言える。プログラマによってはあまり使い道がないと思われているメッソドの実行時バインドだけど、こういう部分で威力を発揮している。また当然、これはC/C++やJavaなどの言語では実現できない。
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

献立04/19献立04/20 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。