Mac用USBデバイス-94 Cocoaバインディングの基礎-2 [Mac用USBデバイス工作]
昨日USBの標準デスクリプタを自動生成するためのUIリッチなアプリを書くために、Cocoaバインディングのおさらいを始めた。今日はその続き。
リソースに含めることのできるメソッドとしてはあまり複雑な引数の形(シグネチャ)のものは使えない。引数になにを指定するか、ということをInterface Builder上で簡単に表現できるほど一般化できないからである。また、リソースの外のオブジェクト(File's Owner以外の)を引数にとることはできないし、またそれをできるようにするとどんどんリソースの独立性が損なわれてこんどはリソースがぐちゃぐちゃになってしまう。
そこでCocoaバインディングのために、いくつかの決まった形のメソッドだけを定義してそれをあらゆるオブジェクトが使えるように、つまりNSObject(のカテゴリ)のメソッドとして導入した。その基本的な考え方は
ただでさえユルい感じのメソッド呼び出しをさらに緩めて結びつきを弱めよう、ということである。異なる変数へのアクセスは文字列で区別されるだけなので、変数がいくつあろうが、オブジェクトが違っていようがそのためのメソッドは完全に共通化できて、おもに
メソッドを呼ぶ側はこのふたつだけですむが、呼ばれる側はこのメソッドを実装しないといけない。また、インスタンス変数としてCocoaのオブジェクトだった場合はいいけど、単なる整数や、Cの構造体の場合もある。そういうときはそれに合わせて実装のやり方を変える必要がある。
しかしCocoaバインディングの場合、このメソッドはインスタンス変数がある規約に沿っていれば自動生成されるようになっていて、その面倒はかなり緩和される。Cocoa/Objective-Cのランタイムはすでに多くの情報を文字列の形で保持している。普通のC/C++なんかではダイナミックリンクの関数名やデバグシンボルとして以外は実行時コードから落ちてしまうが、Cocoa/Objective-Cではクラスの名前やなんとインスタンス変数の名前まで、さらにメソッドもセレクタという文字列として実行時もクラスオブジェクトとランタイムが保持したままなので、後からこういったことが継ぎ足せるということだろう。それにしてもインスタンス変数の名前は少なくともMac OS X10.2のobjc-class.hにはすでにあるんだけど、昔はなにに使ってたんだろう。
変更通知はいにしえのMetrowerks PowerPlantフレームワークにあるbroadcaster-listenerメカニズムと同じである。ただ、PowerPlantがC++の多重継承の機能を使って非常に簡単に実現していたのに対して、Objective-Cではそうはいかなくてisa-swizzlingというアクロバチックなことをやって実現している。詳細はよく理解してないんだけどプロキシオブジェクトのようなものを、暗黙のうちに間にはさんで実現しているらしい。
5.1.2 Cocoaバインディングの技術的な基礎
CocoaバインディングがInterface Builder上で設定できるようにするためには、ControllerとViewが実行すべきメソッドの呼び出しをリソースのなかに含めることができなければならない。昨日、Interface Builderが作るnibファイルの特徴をおさらいしたのはこのため。リソースに含めることのできるメソッドとしてはあまり複雑な引数の形(シグネチャ)のものは使えない。引数になにを指定するか、ということをInterface Builder上で簡単に表現できるほど一般化できないからである。また、リソースの外のオブジェクト(File's Owner以外の)を引数にとることはできないし、またそれをできるようにするとどんどんリソースの独立性が損なわれてこんどはリソースがぐちゃぐちゃになってしまう。
そこでCocoaバインディングのために、いくつかの決まった形のメソッドだけを定義してそれをあらゆるオブジェクトが使えるように、つまりNSObject(のカテゴリ)のメソッドとして導入した。その基本的な考え方は
- インスタンス変数へのアクセスは専用メソッドでなく文字列を使って行う
- インスタンス変数が変更されたとき、やはり文字列を使って変更があったことを伝える
ただでさえユルい感じのメソッド呼び出しをさらに緩めて結びつきを弱めよう、ということである。異なる変数へのアクセスは文字列で区別されるだけなので、変数がいくつあろうが、オブジェクトが違っていようがそのためのメソッドは完全に共通化できて、おもに
- (id)valueForKey:(NSString *)key; - (void)setValue:(id)value forKey:(NSString *)key;のふたつだけになる。変更通知もまったく同じ考え方で行われる。こうやってメソッドを標準化することでModelとViewを結びつけるControllerを専用化せずに汎用のコントローラオブジェクトですますことができるようにしたのがCocoaバインディングであると言っていい。
メソッドを呼ぶ側はこのふたつだけですむが、呼ばれる側はこのメソッドを実装しないといけない。また、インスタンス変数としてCocoaのオブジェクトだった場合はいいけど、単なる整数や、Cの構造体の場合もある。そういうときはそれに合わせて実装のやり方を変える必要がある。
しかしCocoaバインディングの場合、このメソッドはインスタンス変数がある規約に沿っていれば自動生成されるようになっていて、その面倒はかなり緩和される。Cocoa/Objective-Cのランタイムはすでに多くの情報を文字列の形で保持している。普通のC/C++なんかではダイナミックリンクの関数名やデバグシンボルとして以外は実行時コードから落ちてしまうが、Cocoa/Objective-Cではクラスの名前やなんとインスタンス変数の名前まで、さらにメソッドもセレクタという文字列として実行時もクラスオブジェクトとランタイムが保持したままなので、後からこういったことが継ぎ足せるということだろう。それにしてもインスタンス変数の名前は少なくともMac OS X10.2のobjc-class.hにはすでにあるんだけど、昔はなにに使ってたんだろう。
変更通知はいにしえのMetrowerks PowerPlantフレームワークにあるbroadcaster-listenerメカニズムと同じである。ただ、PowerPlantがC++の多重継承の機能を使って非常に簡単に実現していたのに対して、Objective-Cではそうはいかなくてisa-swizzlingというアクロバチックなことをやって実現している。詳細はよく理解してないんだけどプロキシオブジェクトのようなものを、暗黙のうちに間にはさんで実現しているらしい。
2010-04-20 22:13
nice!(0)
コメント(0)
トラックバック(0)
コメント 0