|
|
Log In | Not a Member? |
Contact ADC |
| < Previous PageNext Page > |
デリゲートとは、プログラム内でオブジェクトが何らかのイベントに遭遇したときに、そのオブジェクトに代わって、またはそのオブジェクトと連携して機能するオブジェクトです。委任元オブジェクトは、通常は、レスポンダオブジェクト、つまり、NSResponderを継承し、ユーザイベントに応答するオブジェクトです。デリゲートは、そのイベントに対するユーザインターフェイスの制御を委任されているか、または少なくともアプリケーション固有の方法でイベントを解釈するよう要求されているオブジェクトです。
委任の価値をより深く理解するには、ウインドウ(NSWindowのインスタンス)やテーブルビュー(NSTableViewのインスタンス)など、既製のCocoaオブジェクトに注目するとよいでしょう。これらのオブジェクトは、一般的な方法で特定の役割を果たすように設計されています。たとえば、ウインドウオブジェクトは、物理的なウインドウの終了、リサイズ、移動など、そのコントロールとハンドルのマウス操作に応答します。このように限定された一般的な動作は、必然的に、イベントがアプリケーションの他の部分に与える(または与えることが予想される)影響について、オブジェクトが認識できることを制限します。特に影響を受ける動作がアプリケーション固有のものである場合はなおさらです。委任は、カスタムオブジェクトがアプリケーション固有の動作を既製のオブジェクトに伝える手段を提供します。
委任のプログラミングメカニズムは、プログラム内のどこかほかの場所で生じた変化(通常はユーザアクションにより引き起こされる変化)に伴い、自身の外観と状態を調整する機会をオブジェクトに提供するというものです。さらに重要なことに、委任により、オブジェクトは、そのオブジェクトから継承させることなく、ほかのオブジェクトの動作を変更できます。デリゲートはほとんどの場合カスタムオブジェクトの1つで、定義上は、汎用の、委任元オブジェクトだけでは認識できないようなアプリケーション固有のロジックが組み込みまれています。
委任の仕組み
委任メッセージの形式
委任とApplication Kit
データソース
カスタムクラスのデリゲートの実装
委任メカニズムの設計は単純です(Figure 5-2参照)。委任元のクラスには、アウトレット(通常はdelegateという名前が付けられている)があり、このアウトレットを設定してアクセスするメソッドも含まれています。さらにそのメソッドのいくつかを宣言し(実装はしない)、それらが「簡易プロトコル」を構成します。簡易プロトコルは一般に、委任元クラスのカテゴリとして存在しますが、デリゲートですべてのメソッドをプロトコルに実装する必要がないという点で正式なプロトコルと異なります。デリゲートは、それ自身が委任元オブジェクトと連携したり、当該オブジェクトのデフォルトの動作に作用したりすることに関心がある部分についてのみ、簡易プロトコルのメソッドだけを実装します。
簡易プロトコルのメソッドは、委任元のオブジェクトによって処理または予想された重要なイベントに注目します。このオブジェクトは、これらのイベントをデリゲートに伝達するか、進行中のイベントの場合はデリゲートからの入力や承認を要求することを望んでいます。たとえば、ユーザがウインドウのクローズボタンをクリックすると、ウインドウオブジェクトは windowShouldClose:メッセージをそのデリゲートに送信します。これにより、たとえばウインドウが保存する必要のあるデータと関連している場合は、デリゲートにウインドウのクローズを拒否または延期する機会が与えられます(Figure 5-3を参照)。
委任元のオブジェクトがメッセージを送信するのは、デリゲートがそのメソッドを実装している場合に限られます。これを調べるには、最初に、デリゲートの中でNSObjectメソッドのrespondsToSelector:を呼び出します。この事前のチェックが、簡易プロトコルの設計の鍵となります。
委任メソッドの形式はあらかじめ決められています。委任メソッドは、委任を実行するApplication Kitオブジェクト(アプリケーション、ウインドウ、コントロールなど)の名前で始まります。この名前は小文字で、「NS」プレフィックスは付いていません。通常(常にではない)、このオブジェクト名の次に、報告されたイベントの時間軸上での状態を示す助動詞が続きます。すなわち、この助動詞は、イベントが発生しそうなのか(「Should」または「Will」)、それともすでに発生したのか(「Did」または「Has」)を示します。この時間軸上での区別は、戻り値を期待しているメッセージと期待していないメッセージを分類するのに役立ちます。Listing 5-1に、戻り値を期待しているApplication Kitの委任メソッドをいくつか示します。
Listing 5-1 戻り値のある委任メソッドのサンプル
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename; |
- (BOOL)textShouldBeginEditing:(NSText *)textObject; |
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; |
- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)newFrame; |
これらのメソッドを実装しているデリゲートは、進行中のイベントを(最初の2つでNOを返すことで)ブロックしたり、(applicationShouldTerminate:メソッドでNSTerminateLaterを返すことで)延期したり、推奨されるパラメータ(最後のメソッドのフレーム矩形)を変更したりできます。
他の種類の委任メソッドは、戻り値を期待せず、voidを返すように入力されたメッセージで呼び出されます。このようなメッセージは単に情報を提供するもので、メソッド名にはしばしば「Did」など、イベントが経過したことを示す情報が含まれています。Listing 5-2に、この種の委任メソッドの例をいくつか示します。
Listing 5-2 voidを返す委任メソッドのサンプル
- (void) tableView:(NSTableView*)tableView mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn; |
- (void)applicationDidUnhide:(NSNotification *)notification; |
- (void)applicationWillBecomeActive:(NSNotification *)notification; |
- (void)windowDidMove:(NSNotification *)notification; |
この最後のメッセージ群については、2つのことに注目してください。まず、(3番目のメソッドにあるような)「Will」という助動詞は、戻り値が期待されていることを意味します。この場合、イベントは進行中でブロックできませんが、このメッセージによって委任には、そのイベントのためのプログラムを準備する機会が与えられます。
その他の注目すべき点は、最後の3つのメソッドと関係があります。これらのメソッドのそれぞれの唯一のパラメータはNSNotificationオブジェクトで、それらが特定の通知を発行した結果として呼び出されることを意味します。たとえば、windowDidMove:メソッドは、NSWindowメソッドのNSWindowDidMoveNotificationと結び付いています。通知については“「通知」”のセクションで詳しく説明しますが、ここでは通知と委任メッセージとの関係を理解することが重要です。委任元のオブジェクトは自動的に、自身のデリゲートを、送信するすべての通知のオブザーバに仕立てます。デリゲートが実行する必要があるのは、その通知を受けるための関連メソッドを実装することだけです。
カスタムクラスのインスタンスをApplication Kitオブジェクトのデリゲートに仕立てるには、Interface Builderで、単にインスタンスをdelegateアウトレットに接続します。または委任元のオブジェクトのsetDelegate:メソッドを使用して、awakeFromNibメソッドなどで、なるべく早期にプログラムで設定することができます。
アプリケーションにおいては、委任元のオブジェクトは多くの場合、NSApplicationオブジェクト、NSWindowオブジェクト、またはNSViewオブジェクトです。デリゲートオブジェクト自身は、必ずではありませんが通常はアプリケーションの一部を制御するオブジェクト(つまり調整コントローラオブジェクト)であり、たいてはカスタムオブジェクトです。Table 5-1は、デリゲートが定義されているるApplication Kitクラスを示します。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
委任元のオブジェクト自身は、デリゲートを保持しません(保持してはなりません)。ただし委任元のオブジェクトのクライアント(通常はアプリケーション)は、委任メッセージを受け取るためにデリゲートが存在していることを保証する責任があります。これを行うために、デリゲートを保持する必要が生じることがあります。この対策は、データソース、通知オブザーバ、およびアクションメッセージのターゲットに等しく適用されます。
いくつかのApplication Kitクラスは、「モーダルデリゲート」と呼ばれる、制限されたタイプのデリゲートを使います。このようなクラスのオブジェクト(NSOpenPanelなど)は、ユーザがダイアログの「OK」ボタンをクリックしたときに、指定のデリゲートのハンドラメソッドを呼び出すモーダルダイアログを実行します。モーダルデリゲートの有効範囲は、モーダルダイアログの操作の範囲に限定されます。
デリゲートには、ほかにもプログラム上の用途があります。たとえば、デリゲートを使うと、同じプログラム内の連携する2つのコントローラが、容易に互いを探しあてて通信できます。たとえば、アプリケーション全体を制御するオブジェクトは、次のようなコードを使って、アプリケーションのインスペクタウインドウ(それが現在のキーウインドウと仮定すると)のコントローラを見つけることができます。
id winController = [[NSApp keyWindow] delegate]; |
また、次のようなコードを実行することで、アプリケーションコントローラオブジェクト(つまり、グローバルなアプリケーションインスタンスのデリゲート)を見つけることができます。
id appController = [NSApp delegate]; |
データソースはデリゲートに似ていますが、ユーザインターフェイスの制御ではなく、データの制御を委任されます。データソースは、テーブルビューやアウトラインビューなど、可視データの行を代入するためのソースを必要とするNSViewオブジェクトが持つアウトレットです。ビューのデータソースは、通常はそのデリゲートとして機能するオブジェクトと同じオブジェクトですが、どのようなオブジェクトでも構いません。デリゲートと同様、データソースは必要なデータをビューに供給し、より高度な実装では、そのようなビューでユーザが直接編集するデータを処理するために、簡易プロトコルのメソッドを1つ以上実装する必要があります。
デリゲートと同様、データソースは、データを要求しているオブジェクトからのメッセージを受信するために必要なオブジェクトです。データソースを使用するアプリケーションは、必要であればデータソースを保持することで、その存続を保証する必要があります。
データソースは、ユーザインターフェイスオブジェクトへ渡すオブジェクトの永続性を維持する責任があります。言い換えると、これらのオブジェクトのメモリ管理の責任があるということです。ただし、アウトラインビューやテーブルビューなどのビューオブジェクトがデータソースのデータにアクセスする場合、そのデータを使用している間は、必ずビューオブジェクトがデータソースオブジェクトを保持します。ただし長い時間データを使用することはありません。通常は、データの表示に必要な間しか保持しません。
カスタムオブジェクトにデリゲートを実装するには、次の手順を実行します。
クラスヘッダファイルに、デリゲートアクセサメソッドを宣言します。
- (id)delegate; |
- (void)setDelegate:(id)newDelegate; |
アクセサメソッドを実装します。setterメソッドでは、デリゲートへの弱い参照のみを使用して、保持の循環を避ける(つまり、デリゲートのコピーまたは保持を避ける)必要があります。
- (id)delegate { |
return delegate; |
} |
- (void)setDelegate:(id)newDelegate { |
delegate = newDelegate; |
} |
デリゲートのプログラムインターフェイスを含む簡易プロトコルを宣言します。簡易プロトコルは、NSObjectクラスのカテゴリです。
@interface NSObject (MyObjectDelegateMethod) |
- (BOOL)operationShouldProceed; |
@end |
カスタムデリゲートメソッドの命名方法の詳細については、“「委任メッセージの形式」”を参照してください。
委任メソッドを呼び出す前に、respondsToSelector:メッセージを送信してデリゲートがそれを実装していることを確認します。
- (void)someMethod { |
if ( [delegate respondsToSelector:@selector(operationShouldProceed)] ) { |
if ( [delegate operationShouldProceed] ) { |
// 適切な処理をする |
} |
} |
} |
| < Previous PageNext Page > |
Last updated: 2006-05-23
|
Get information on Apple products.
Visit the Apple Store online or at retail locations. 1-800-MY-APPLE Copyright © 2007 Apple Inc. All rights reserved. | Terms of use | Privacy Notice |