|
|
Log In | Not a Member? |
Contact ADC |
| < Previous PageNext Page > |
Cocoaでは、全体を通じてデザインパターンの応用が見られます。パターンに基づくメカニズムやアーキテクチャが、CocoaのフレームワークやObjective-Cランタイムおよび言語に共通して見られます。Cocoaでは多くの場合、パターンに対して独自の特徴付けが行われており、そのデザインは言語の機能や既存のアーキテクチャなどの要素の影響を受けています。
このセクションには、『Design Patterns: Elements of Reusable Object-Oriented Software』で分類されているほとんどのデザインパターンに対応した項目があります。それぞれの項目では、パターンの概要を示し、Cocoaにおける当該パターンの実装を説明します。ここではCocoaで実装されているパターンだけを列挙しており、以降の各セクションでは、それぞれのパターンをCocoaの特定のコンテキストの中で説明しています。これらのパターンはCocoaのソフトウェア開発で役に立つので、十分に理解することをお勧めします。
Cocoaでは、デザインパターンがさまざまな形で実装されています。以降の各セクションで説明するデザインの中には、Objective-C言語の機能であるもの(プロトコルやカテゴリなど)があります。また、“パターンのインスタンス”が、1つのクラスまたは関連するクラスのグループに実装されているものもあります(クラスクラスタやシングルトンクラスなど)。さらに、パターンの応用が主要なフレームワークアーキテクチャになっているもの(レスポンダチェーンなど)もあります。パターンベースのメカニズムには、ほとんど“負担なし”で得られるものもあれば、開発者の側で何らかの作業を必要とするものもあります。そして、Cocoaでパターンが実装されていない場合でも、状況が許せば、自分でパターンを実装することをお勧めします。たとえば、クラスの動作を拡張する場合、サブクラス化よりもオブジェクト構成(Decoratorパターン)のほうが手法として適切な場合が多くあります。
Model-View-Controller (MVC)とオブジェクトモデリングの2つのデザインパターンについては、このセクションでは説明していません。MVCは複合パターンまたは集約パターンです。これは、複数のカタログパターンがベースとなっていることを意味します。オブジェクトモデリングはGang of Fourのカタログに対応するものがなく、リレーショナルデータベースの分野に由来するものです。とはいえ、MVCとオブジェクトモデリングは、おそらくCocoaにおいて最も重要で普遍的なデザインパターンまたはメタファであり、大部分が互いに関連し合うパターンです。これらは、バインディング、取り消し管理、スクリプティング、ドキュメントアーキテクチャといった、いくつかの技術のデザインにおいて、たいへん重要な役割を果たします。これらのパターンの詳細については、“「Model-View-Controllerデザインパターン」”および“「オブジェクトモデリング」”を参照してください。
Abstract Factory
Adapter
Chain of Responsibility
Command
Composite
Decorator
Facade
Iterator
Mediator
Memento
Observer
Proxy
Singleton
Template Method
関連し合うオブジェクトや依存し合うオブジェクトのファミリを、具象クラスを指定せずに作成するためのインターフェイスを提供します。クライアントは、ファクトリから得られる具象オブジェクトのどの詳細からも切り離されています。
クラスクラスタは、いくつかのプライベートの具象サブクラスを、パブリックの抽象スーパークラスの下にグループ化するアーキテクチャです。抽象スーパークラスでは、自身のプライベートサブクラスのインスタンスを生成するためのメソッドを宣言します。スーパークラスは、呼び出された生成メソッドに応じて、適切な具象サブクラスのオブジェクトを生成します。返されるオブジェクトはそれぞれ、異なるプライベートの具象サブクラスに属する可能性があります。
Cocoaにおけるクラスクラスタの使用は、データ格納域が状況に応じて変化する可能性のあるオブジェクトの生成に限定されています。Foundationフレームワークには、NSString、NSData、NSDictionary、NSSet、NSArrayの各オブジェクトに対応したクラスクラスタがあります。パブリックスーパークラスには、上記の不変クラスだけでなく、その補助的な可変クラスであるNSMutableString、NSMutableData、NSMutableDictionary、NSMutableSet、NSMutableArrayの各クラスも含まれます。
クラスタによって表される型の不変または可変のオブジェクトを作成したい場合は、クラスクラスタのパブリッククラスの1つを使用します。クラスクラスタでは、単純さを取るか拡張性を取るかというトレードオフがあります。クラスクラスタによってクラスへのインターフェイスが単純になり、したがって、クラスの習得や使用も容易になります。しかし、一般にクラスクラスタの抽象クラスからカスタムサブクラスを作成することは難しくなります。
参考資料: Cocoaのクラスクラスタの詳細については、“「クラスクラスタ」”を参照してください。
クラスのインターフェイスを、クライアントで想定している別のインターフェイスに変換します。Adapterは、本来インターフェイスの互換性がないために連携して動作できないクラスどうしが、連携して動作できるようにします。Adapterによって、クライアントは対象のオブジェクトのクラスから切り離されます。
プロトコルは、Adapterパターンのインスタンスであるインターフェイスを定義できるようにする言語レベル(Objective-C)の機能です(Javaの“インターフェイス”は“プロトコル”と同義です)。クライアントオブジェクトどうしがやり取りをする必要があるものの、インターフェイスの互換性がないためにそれが困難である場合に、プロトコルを定義することができます。プロトコルは、本質的にはクラスに関連付けられていない一連のメソッド宣言です。やり取りの相手となるオブジェクトのクラスでは、定義されたそのプロトコルを正式に採用し、プロトコルのすべてのメソッドを実装することによってプロトコルに“準拠”することができます。以後、クライアントオブジェクトから、相手のオブジェクトに、プロトコルインターフェイスを通じてメッセージを送信できるようになります。
プロトコルによって、一連のメソッド宣言がクラス階層に依存しなくなり、クラス継承だけでなくプロトコルへの準拠を基準としてオブジェクトをグループ化できるようになります。NSObjectのメソッドconformsToProtocol:を使用すると、オブジェクトがプロトコルに準拠しているかどうかを確認できます。
Cocoaでは、正式プロトコルに加えて簡易プロトコルの概念もあります。このタイプのプロトコルはNSObjectクラスのカテゴリです。したがって、任意のオブジェクトが、カテゴリ内の任意のメソッドを実装する候補になります(“「カテゴリ」”を参照)。簡易プロトコルのメソッドは選択的に実装できます。簡易プロトコルは委任メカニズムの実装の一部です(“「委任」”を参照)。
プロトコルのデザインはAdapterパターンと完全に一致するわけではありませんが、本来インターフェイスの互換性がないために連携して動作できないクラスどうしを、連携して動作できるようにするための手段になります。
プロトコルは主として、階層的に関連のないクラスどうしが互いにやり取りする必要がある場合に、それらのクラスが準拠することが求められるインターフェイスを宣言するために使用します。ただし、プロトコルを使用して、オブジェクトのクラスを隠蔽したまま、オブジェクトのインターフェイスを宣言することもできます。Cocoaのフレームワークには、カスタムサブクラスどうしが特定の目的で互いにやり取りできるようにするための正式プロトコルが多数組み込まれています。たとえば、FoundationフレームワークにはNSObject、NSCopying、NSCodingの各プロトコルが組み込まれていますが、これらは皆たいへん重要なプロトコルです。Application Kitのプロトコルには、NSDraggingInfo、NSTextInput、およびNSChangeSpellingがあります。
正式プロトコルに準拠しようとするクラスでは、宣言されているすべてのメソッドを実装する必要があります。これらのプロトコルには影響を受けやすいという性質もあります。プロトコルを定義してほかのクラスで使用できるようにした場合、将来プロトコルに変更が加えられるとそれらのクラスが正しく動作しなくなる可能性があります。
要求を処理するための機会を複数のオブジェクトに与えることによって、要求の送信者がその受信者に結び付くのを防ぎます。受信側オブジェクトをひとつなぎのチェーンとして連結し、いずれかのオブジェクトが要求を処理するまで要求をチェーンに沿って受け渡しします。各オブジェクトは、要求を処理するか、要求をチェーンの次のオブジェクトに渡すかのどちらかを実行します。
Application Kitフレームワークには、レスポンダチェーンと呼ばれるアーキテクチャが組み込まれています。このチェーンは一連のレスポンダオブジェクト(つまり、NSResponderを継承するオブジェクト)で構成され、チェーンに沿ってイベントメッセージ(マウスクリックなど)やアクションメッセージが渡され、(通常は)いずれかのオブジェクトで処理されます。それぞれのレスポンダオブジェクトは、特定のメッセージを処理しない場合、そのメッセージをチェーンの次のレスポンダに渡します。一般に、チェーン内のレスポンダオブジェクトの順序はビュー階層によって決まり、階層内で下位レベルのレスポンダから上位レベルのレスポンダに向かい、最終的に、ビュー階層を管理しているウインドウオブジェクトか、ウインドウオブジェクトのデリゲート、またはグローバルアプリケーションオブジェクトに到達します。レスポンダチェーンの上位に向かうイベントメッセージおよびアクションメッセージの正確なパスはそれぞれ異なります。アプリケーションでは、ウインドウ(またはローカルなビュー階層)の数だけいくつでもレスポンダチェーンを持つことができます。ただし、アクティブになれるレスポンダチェーンは一度に1つだけで、現在アクティブなウインドウに関連付けられているレスポンダチェーンのみです。
アプリケーションのエラー処理を行うための同様のレスポンダチェーンも存在します。
ビュー階層のデザインはレスポンダチェーンと密接に関連していますが、このデザインはCompositeパターン(“「Composite」”)を応用したものです。アクションメッセージ(コントロールオブジェクトから発信されるメッセージ)はターゲット/アクションメカニズムに基づいています。このメカニズムはCommandパターン(“「Command」”)のインスタンスです。
Interface Builderを使用して、またはプログラミングを行って、プログラムのユーザインターフェイスを作成すると、“何もしなくても”1つ以上のレスポンダチェーンを得ることになります。レスポンダチェーンはビュー階層と連動しています。ビュー階層は、ビューオブジェクトをウインドウのコンテンツビューのサブビューにしたときに自動的に得られます。ビュー階層にカスタムビューを追加してある場合、そのカスタムビューはレスポンダチェーンの一部になり、NSResponderの適切なメソッドを実装することで、イベントメッセージやアクションメッセージを受け取って処理できます。ウインドウオブジェクトのデリゲートであるカスタムオブジェクト、またはNSApp(グローバルアプリケーションオブジェクト)のデリゲートであるカスタムオブジェクトもまた、それらのメッセージを受け取って処理できます。
プログラミングを行って、カスタムのレスポンダをレスポンダチェーンに挿入したり、レスポンダの順序を操作したりすることもできます。
参考資料: イベントメッセージやアクションメッセージ用のレスポンダチェーンと、エラー処理用のレスポンダチェーンの詳細については、それぞれ、『Event Handling Programming Guide for Cocoa』および『Error Handling Programming Guide For Cocoa』を参照してください。この文書では、ビュー階層の概要を“「Composite」”パターンのセクションで説明します。ビュー階層の詳細については、“「コアアプリケーションアーキテクチャ」”を参照してください。
要求をオブジェクトとしてカプセル化し、それによって、クライアントを異なる要求ごとにパラメータ化したり、要求をキューに置いたり、要求をログに記録したり、取り消しが可能な操作をサポートしたりできるようにします。要求オブジェクトは、特定のレシーバに対する1つ以上のアクションをひとまとめにします。Commandパターンによって、要求を行うオブジェクトと、要求を受け取って実行するオブジェクトとが切り離されます。
Objective-CのメッセージはNSInvocationクラスのインスタンスによってカプセル化されます。呼び出しオブジェクトには、ターゲットオブジェクト、メソッドセレクタ、およびメソッド引数が含まれます。呼び出しオブジェクトによってディスパッチされるメッセージのターゲットやその引数は、動的に変更できます。いったん呼び出しが実行されると、その戻り値をオブジェクトから取得することもできます。1つの呼び出しオブジェクトを使用し、ターゲットまたは引数のバリエーションを複数持つメッセージを、繰り返し呼び出すことができます。
NSInvocationオブジェクトを作成するにはNSMethodSignatureオブジェクトが必要になります。これは、メソッドの引数と戻り値に関連する型情報をカプセル化するオブジェクトです。NSMethodSignatureオブジェクトはメソッドセレクタから作成されます。NSInvocationの実装ではObjective-Cランタイムの関数も利用されています。
NSInvocationオブジェクトは、分散オブジェクト、取り消し管理、メッセージ転送、タイマーの各プログラムインターフェイスの一部になっています。呼び出しオブジェクトは、メッセージを送信するオブジェクトとメッセージを受信するオブジェクトとを切り離す必要があるような同様のコンテキストの中で使用することもできます。
分散オブジェクトは、プロセス間通信のための技術です。分散オブジェクトの詳細については、“「Proxy」”を参照してください。
参考資料: 呼び出しオブジェクトの詳細については、NSInvocationクラスのリファレンスドキュメントを参照してください。また、関連する各技術の詳細については、『Distributed Objects』、『Undo Architecture』、『Timers』、および『The Objective-C Programming Language』の転送のセクションを、それぞれ参照してください。
ターゲット/アクションメカニズムは、コントロールオブジェクト(ボタン、スライダ、テキストフィールドなど)から、メッセージを解釈してアプリケーション固有の命令として処理できる別のオブジェクトに、メッセージを送信することを可能にします。受信側のオブジェクト、つまりターゲットは、通常はカスタムコントローラオブジェクトです。メッセージ(アクションメッセージと呼ばれます)は、メソッドの一意の実行時識別子であるセレクタによって判別されます。コントロールが所有しているセルオブジェクトでは通常、ターゲットとアクションがカプセル化されており、ユーザがコントロールをクリックしたときや、それ以外の方法でコントロールをアクティブにしたときに、コントロールからメッセージが送信されます(メニュー項目でもターゲットとアクションがカプセル化されており、メニュー項目が選ばれるとその項目からアクションメッセージが送信されます)。ターゲット/アクションメカニズムは(メソッドシグネチャではなく)セレクタに基づいて機能できます。これは、アクションメソッドのシグネチャは慣例上常に同じであるためです。
コントロールのアクションとターゲットは、Interface Builderアプリケーションを使用してプログラムのユーザインターフェイスを作成する際に設定できます。そうすることで、コントロールそのもののコードをまったく記述せずに、コントロールでカスタムの動作を開始させることができます。アクションセレクタとターゲットの接続はnibファイルにアーカイブされ、nibの展開時に復元されます。コントロールやそのセルにsetTarget:またはsetAction:メッセージを送信して、ターゲットやアクションを動的に変更することもできます。
ターゲット/アクションはこれまで、ユーザインターフェイスからモデルオブジェクトにデータを転送したり、データをモデルオブジェクトに表示したりするよう、カスタムコントローラオブジェクトに指示するためにしばしば使用されてきました。Cocoaバインディング技術により、ターゲット/アクションをこの用途に使用する必要はなくなっています。この技術の詳細については、『Cocoa Bindings Programming Topics』を参照してください。
Application Kitのコントロールやセルでは、自身のターゲットは保持せず、代わりにデリゲートやデータソースへの弱い参照を維持します。詳細については、“「デリゲート、オブザーバ、ターゲットの所有権」”を参照してください。
参考資料: 詳細については、“「ターゲット/アクションメカニズム」”を参照してください。
関連するオブジェクトを、部分全体階層を表すツリー構造に構成します。Compositeによって、クライアントでは個々のオブジェクトとオブジェクトの構成を一様に扱うことができるようになります。
CompositeパターンはModel-View-Controller集約パターンの一部です。
ウインドウ内のビュー(NSViewオブジェクト)は、内部的にビュー階層に構造化されます。階層のルートにはウインドウ(NSWindowオブジェクト)とそのコンテンツビューがあります。コンテンツビューは、ウインドウのコンテンツ矩形を埋める透明のビューです。コンテンツビューに追加されるビューは、コンテンツビューのサブビューになり、サブビューに追加されるすべてのビューのスーパービューになります。ビューは、スーパービューを1つ(のみ)と、0個以上のサブビューを持つことができます。視覚的には、この構造はスーパービューにそのサブビューが含まれているものと捉えることができます。Figure 4-2は、ビュー階層の構造的な側面と視覚的な側面を示します。
ビュー階層は、描画とイベント処理の両方に関与する構造的なアーキテクチャです。ビューには、フレームと境界という2つの境界矩形があります。ビューに関するグラフィック操作がどのように行われるかは、これらの境界矩形に左右されます。フレームは外側の境界であり、ビューをスーパービューの座標系の中で配置し、そのサイズを定義し、図形をその端でクリップします。境界は内側の境界矩形であり、ビュー自身が描画される表面の内部座標系を定義します。
ウインドウは、ウインドウ処理システムから表示の準備をするように要求されると、スーパービューは、そのサブビューよりも前に自身をレンダリングするよう要求されます。プログラムから何らかのメッセージ(自身を再描画することを要求するメッセージなど)をビューに送信すると、メッセージがサブビューにまで伝達されます。したがって、ビュー階層の分岐を統一的なビューとして扱うことができます。
また、ビュー階層は、レスポンダチェーンによってイベントメッセージやアクションメッセージの処理にも使用されます。レスポンダチェーンの概要については、Chain of Responsibilityパターン項目(“「Chain of Responsibility」”)の説明を参照してください。
Interface Builderを使用して、またはプログラムから、ビューを別のビューに追加するたびにビュー階層を作成または変更することになります。ビュー階層に関連する関係は、Application Kitフレームワークによってすべて自動的に処理されます。
参考資料: ビュー階層の詳細については、この文書の“「ビュー階層」”を参照してください。『Cocoa Drawing Guide』も参照してください。
追加の責任をオブジェクトに動的に付加します。Decoratorは、サブクラス化の代わりとなる、機能を拡張するための柔軟な手段を提供します。サブクラス化と同様に、既存のコードに変更を加えなくても、Decoratorパターンを応用することで新しい動作を組み込むことが可能になります。Decoratorは、動作を拡張する対象となるクラスのオブジェクトをラップします。対象オブジェクトと同じインターフェイスを実装し、対象オブジェクトへの処理の委任前または委任後に、独自の動作を追加します。Decoratorパターンは、クラスの拡張に対しては門戸を開きつつ、変更に対しては閉じている必要があるというデザイン原則を示します。
Decoratorはオブジェクト構成のためのパターンです。オブジェクト構成は自分のコードの中で実現することが推奨されている作業です(“「サブクラスの作成を必要とする場合」”を参照)。ただし、Cocoaにはこのパターンに基づく独自のクラスとメカニズムが用意されています(以降の各セクションを参照)。これらの実装では、拡張を行うオブジェクトは、ラップ対象オブジェクトのインターフェイスを完全には複製しません。しかし、それらの実装では、インターフェイスを共有するためのさまざまな技術が使用されています。
Cocoaでは、NSAttributedString、NSScrollView、NSTableViewなどのいくつかのクラスの実装でDecoratorパターンを使用しています。最後の2つのクラスは複合ビューの例です。複合ビューは、ほかのビュークラスの単純オブジェクトどうしをグループ化してそれらのやり取りを調整するものです。
委任は、ホストオブジェクトに別のオブジェクト(ホストのデリゲート)への弱い参照(保持されないアウトレット)が埋め込まれ、処理のための入力を必要とするときにデリゲートに定期的にメッセージが送信されるメカニズムです。通常、ホストオブジェクトは、何らかの処理の達成を試みるものの、汎用的な方法でのみその処理を実行する、“既製の”フレームワークオブジェクト(NSWindowやNSXMLParserなどのオブジェクト)です。デリゲートは、ほぼ必ずカスタムクラスのインスタンスですが、ホストオブジェクトと協調して動作し、処理の特定の時点でプログラム固有の動作を提供します(Figure 4-3を参照)。このように、委任により、サブクラス化を行わなくても、別のオブジェクトの動作を変更または拡張することが可能になります。
あるオブジェクトの処理を別のオブジェクトに任せるというだけの意味においては、委任はオブジェクト指向プログラミングにおける一般的な手法です。しかし、Cocoaでは委任が独自の方法で実装されています。ホストクラスでは、簡易プロトコル(NSObjectのカテゴリ)を使用して、デリゲートオブジェクトにおいて実装することを選択できるインターフェイスを定義します。デリゲートでは、正式プロトコルの場合のようにプロトコルのすべてのメソッドを実装する必要は必ずしもありません。実行時の例外を避けるために、ホストオブジェクトはメッセージをデリゲートに送る前に、デリゲートがメソッドを実装しているかどうかを(respondsToSelector:メッセージを通じて)調べます。正式プロトコルと簡易プロトコルの詳細については、“「プロトコル」”を参照してください。
Cocoaフレームワークのクラスの中には、自身のデータソースにメッセージを送信するものもあります。データソースはすべての面でデリゲートとまったく同じですが、ブラウザ、テーブルビュー、または同様のユーザインターフェイスビューに設定するデータをホストオブジェクトに提供することを目的とする点が異なります。また、データソースはデリゲートとは異なり、プロトコルの何らかのメソッドを実装することが必須の場合もあります。
委任はDecoratorパターンを厳密に実装したものではありません。ホスト(委任元の)オブジェクトは、拡張対象クラスのインスタンスをラップすることはありません。むしろ逆で、デリゲートが、委任元のフレームワーククラスの動作をカスタマイズすることになります。また、フレームワーククラスに宣言されている委任メソッドを除けば、インターフェイスを共有することもありません。
Cocoaの委任はTemplate Methodパターン(“「Template Method」”)の一部にもなっています。
委任はCocoaのフレームワークにおいて一般的なデザインになっています。Application Kitフレームワークの多くのクラスがメッセージをデリゲート(NSApplication、NSWindow、およびNSViewのいくつかのサブクラスなど)に送ります。Foundationフレームワークの一部のクラス(NSXMLParserやNSStreamなど)も、デリゲートを維持しています。委任メソッドを使用しても目的を達成できない場合を除き、クラスをサブクラス化せずに、必ずクラスの委任メカニズムを使用してください。
デリゲートを動的に変更することは可能ですが、デリゲートになれるのは一度に1つのオブジェクトだけです。したがって、特定のプログラムイベントを複数のオブジェクトに同時に通知する必要がある場合は、委任は使用できません。ただし、この目的の場合には通知メカニズムを使用できます。デリゲートでは、フレームワーククラスに宣言されている通知メソッドを1つ以上実装している限り、委任元のフレームワークオブジェクトから自動的に通知を受信します。詳細については、Observerパターン(“「Observer」”)の通知の説明を参照してください。
Application Kitの委任元オブジェクトは、自身のデリゲートやデータソースは保持せず、代わりにデリゲートやデータソースへの弱い参照を維持します。詳細については、“「デリゲート、オブザーバ、ターゲットの所有権」”を参照してください。
参考資料: 委任の詳細については、“「デリゲートとデータソース」”を参照してください。
カテゴリは、サブクラスを作成しなくてもメソッド(インターフェイスと実装)をクラスに追加できるようにするObjective-C言語の機能です。クラスの元のメソッドと、カテゴリによって追加されたメソッドとで、実行時の違いは(プログラムの有効範囲内において)まったくありません。カテゴリ内のメソッドはクラスの型の一部になり、クラスのすべてのサブクラスに継承されます。
委任と同様に、カテゴリはDecoratorパターンの厳密な応用ではありません。同じ意図を実現しますが、その意図を実装するために別の手段を用いています。カテゴリによって追加される動作はコンパイル時の生成物であり、動的に取得されるものではありません。また、カテゴリでは、拡張対象クラスのインスタンスはカプセル化されません。
Cocoaのフレームワークでは多数のカテゴリが定義されており、そのほとんどは簡易プロトコルです(簡易プロトコルの概要については“「プロトコル」”で説明しています)。Cocoaのフレームワークでは多くの場合、関連するメソッド群をグループ化する目的でカテゴリを使用しています。コードにカテゴリを実装することで、サブクラス化をせずにクラスを拡張したり、関連するメソッドをグループ化したりできます。ただし、次の点に注意してください。
クラスにインスタンス変数を追加できません。
クラスの既存のメソッドをオーバーライドすると、アプリケーションが、予期しない動作をする場合があります。
サブシステム内の一連のインターフェイスに対する統合されたインターフェイスを提供します。Facadeは、複雑さを減らし、サブシステム間の通信や依存関係を隠蔽することによって、サブシステムを使いやすくする、より高次元のインターフェイスを定義するものです。
NSImageは、ビットマップベース(JPEG、PNG、TIFF形式など)またはベクトルベース(EPSやPDF形式など)の画像をロードして使用するための、統合されたインターフェイスを提供するクラスです。NSImageでは、同じ画像を複数の表現で保持できます。表現はそれぞれNSImageRepオブジェクトの一種になります。NSImageは、特定の種類のデータや対象の表示デバイスに適した表現を選択する処理を自動化します。また、画像の操作や選択に関する詳細を隠蔽するので、クライアントが、多数の異なる基礎的な表現を違いなく使用できます。
NSImageでは、画像について複数の異なる表現をサポートしているため、要求された属性が該当しない場合があります。たとえば、基礎となる表現がベクトルベースで、デバイス非依存の場合、画像のピクセル色を要求しても求めている結果は得られません。
集約オブジェクトの基盤表現を開示せずに、集約オブジェクト(つまり、コレクション)の要素に順にアクセスできるようにするための手段を提供します。Iteratorパターンは、コレクションの要素へのアクセスと要素間の移動を行う責任を、コレクション自身から反復子オブジェクトに移します。反復子は、コレクションの要素にアクセスするためのインターフェイスを定義し、カレント要素を追跡します。反復子が従う移動のポリシーは反復子ごとに異なります。
FoundationフレームワークのNSEnumeratorクラスは、Iteratorパターンを実装しています。NSEnumerator抽象クラスのプライベート具象サブクラスは、列挙子オブジェクトを返します。この列挙子オブジェクトは、各種のコレクション(配列、集合、辞書(値とキー)など)を順に移動し、コレクション内のオブジェクトをクライアントに返します。
NSDirectoryEnumeratorは、わずかながら関連のあるクラスです。このクラスのインスタンスは、ファイルシステム内のディレクトリの内容を再帰的に列挙します。
NSArray、NSSet、NSDictionaryなどのコレクションクラスには、コレクションの型に適した列挙子を返すメソッドが組み込まれています。列挙子はすべて同じように動作します。ループの中で、nextObjectメッセージを列挙子オブジェクトに送ります。ループは、コレクション内の次のオブジェクトの代わりにnilが返された時点で終了します。
1組のオブジェクトどうしのやり取り方法をカプセル化するオブジェクトを定義します。Mediatorでは、オブジェクトどうしが互いに明示的に参照し合わないようにすることで緩やかな結合が促進され、オブジェクトどうしのやり取りを個別に変化させることができるようになります。そのため、これらのオブジェクトの再利用性の高さを維持できます。
Mediatorオブジェクトでは、システムにおけるオブジェクト間の複雑な通信や制御のロジックが集中化されます。これらのオブジェクトは、各自の状態が変化したときにそのことをMediatorオブジェクトに伝えます。また、Mediatorからの要求に応答します。
Model-View-Controllerデザインパターンでは、オブジェクト指向システム内のオブジェクト(アプリケーションなど)に、役割が割り当てられます。これらのオブジェクトは、モデルオブジェクト(アプリケーションのデータを格納し、そのデータを操作するオブジェクト)であったり、ビューオブジェクト(データを表示し、ユーザの操作に応えるオブジェクト)であったり、コントローラオブジェクト(モデルオブジェクトとビューオブジェクトを仲介するオブジェクト)であったりします。この中で、コントローラオブジェクトがMediatorパターンに該当します。
Cocoaのコントローラオブジェクトは、大きく分けて仲介コントローラと調整コントローラの2種類があります。仲介コントローラは、アプリケーションにおいて、ビューオブジェクトとモデルオブジェクトとの間のデータの流れに仲介します。通常、仲介コントローラはNSControllerオブジェクトです。調整コントローラは、アプリケーション用の集中化された通信および制御のロジックを実装し、フレームワークオブジェクトのデリゲートとして、また、アクションメッセージのターゲットとして、機能します。通常、これらはNSWindowControllerオブジェクトか、NSObjectのカスタムサブクラスのインスタンスです。調整コントローラは特定のプログラム向けにきわめて特化しているので、再利用しにくい傾向があります。
Application Kitフレームワークにある抽象クラスNSControllerとその具象サブクラス群は、Cocoaの技術であるバインディングの一部です。バインディングは、モデルオブジェクトに格納されているデータと、ビューオブジェクトで表示および編集されるデータとの同期を自動的に行うものです。たとえば、ユーザがテキストフィールドの文字列を編集した場合、バインディングによって、その変更が仲介コントローラを通じて、バインド対象モデルオブジェクトの該当するプロパティに伝達されます。プログラマがしなければならないことは、モデルオブジェクトを適切に設計し、Interface Builderを使用して、プログラムのビューオブジェクト、コントローラオブジェクト、およびモデルオブジェクト間でバインディングを確立することだけです。
具象パブリックコントローラクラスのインスタンスはInterface Builderパレット上で使用できるため、再利用性が高くなっています。これらのインスタンスは、選択やプレースホルダ値の管理などのサービスを提供します。これらのオブジェクトは次に示す特定の機能を実行します。
NSObjectControllerは、単独のモデルオブジェクトを管理します。
NSArrayControllerは、モデルオブジェクトの配列を管理し、選択を維持します。また、配列に対するオブジェクトの追加と削除を可能にします。
NSTreeControllerは、階層ツリー構造のモデルオブジェクトの追加、削除、および管理を可能にします。
NSUserDefaultsControllerは、環境設定(ユーザのデフォルト設定)システムへの便利なインターフェイスを提供します。
NSControllerオブジェクトは、アプリケーションのビューオブジェクトとモデルオブジェクトとの間でのデータ通信を目的として設計されているため、通常は仲介コントローラとして使用します。通常、仲介コントローラを使用するには、Interface Builderパレットからオブジェクトをドラッグし、モデル-オブジェクトプロパティのキーを指定します。そして、Interface Builderの情報ウインドウにある「Bindings」ペインを使用して、ビューオブジェクトとモデルオブジェクト間のバインディングを確立します。NSController、またはそのサブクラスをサブクラス化して、より詳細なカスタマイズを動作に加えることもできます。
オブジェクトがNSKeyValueCodingおよびNSKeyValueObserving簡易プロトコルに準拠している限り、ほとんどすべてのオブジェクトペアの間でバインディングを確立できます。しかし、NSControllerとそのサブクラスによってもたらされる利点をすべて享受できるように、仲介コントローラを通じてバインディングを行うことをお勧めします。
調整コントローラは、次の手段によってアプリケーションの通信および制御のロジックを集中化します。
モデルオブジェクトとビューオブジェクトへのアウトレットを維持します(アウトレットとは、インスタンス変数として保持されているほかのオブジェクトへの接続または参照のことです)。
ユーザによるビューオブジェクトの操作に対してターゲット/アクションを通じて応答します(“「ターゲット/アクション」”を参照)。
フレームワークオブジェクトから送信されるメッセージのデリゲートとして機能します(“「委任」”を参照)。
上記の接続(アウトレット、ターゲット/アクション、およびデリゲート)は、通常はすべてInterface Builderで作成します。Interface Builderではそれらの接続がアプリケーションのnibファイルにアーカイブされます。
参考資料: 仲介コントローラ、調整コントローラ、およびコントローラに関連するデザインの決定の詳細については、“「Model-View-Controllerデザインパターン」”を参照してください。仲介コントローラクラスの詳細については、『Cocoa Bindings Programming Topics』を参照してください。
カプセル化に違反せずに、オブジェクトの内部状態を取得し、外部化することによって、後でオブジェクトをその状態に戻せるようにします。Mementoパターンでは、主要なオブジェクトの重要な状態をそのオブジェクトの外部に置くことで結合が維持されます。
アーカイブは、プログラム内のオブジェクトをそのプロパティ(属性と関係)と一緒にアーカイブに変換するものです。アーカイブはファイルシステムに格納したり、プロセス間やネットワーク経由で送信したりできます。アーカイブには、プログラムのオブジェクトグラフが、アーキテクチャに依存しないバイトストリームとして格納されます。このバイトストリームでは、オブジェクトの識別情報とオブジェクト間の関係が保たれます。オブジェクトの型が、データと一緒に格納されるため、バイトストリームからデコードされたオブジェクトは通常、エンコードされていたオブジェクトと同じクラスを使用してインスタンス化されます。
通常は、プログラム内のオブジェクトのうち、状態を保存する必要のあるオブジェクトをアーカイブします。モデルオブジェクトは、ほとんど必ずこの部類に該当します。オブジェクトをアーカイブに書き込むにはオブジェクトをエンコードし、アーカイブからそのオブジェクトを読み取るにはオブジェクトをデコードします。エンコードとデコードの操作はNSCoderオブジェクトを使用して実行します。可能な限り、キーアーカイブの手法を使用することをお勧めします(NSKeyedArchiverクラスとNSKeyedUnarchiverクラスのメソッドを呼び出す必要があります)。エンコードおよびデコードの対象となるオブジェクトはNSCodingプロトコルに準拠している必要があります。アーカイブ時にはこのプロトコルのメソッドが呼び出されます。
プロパティリストは、NSDictionary、NSArray、NSString、NSData、NSDate、およびNSNumberクラスのオブジェクトのみを使用したオブジェクトグラフを、単純な構造でシリアライズしたものです。通常、上記のオブジェクトのことをプロパティリストオブジェクトと呼びます。Cocoaフレームワーククラスには、これらのプロパティリストオブジェクトをシリアライズし、オブジェクトの内容とその階層関係を記録するデータストリームのための特殊な形式を定義するメソッドを提供しているものがいくつかあります。NSPropertyListSerializationクラスには、XML形式または最適化されたバイナリ形式からプロパティリストオブジェクトに(またはプロパティリストオブジェクトからXML形式または最適化されたバイナリ形式に)シリアライズするためのメソッドが用意されています。
オブジェクトグラフ内のオブジェクトが単純な場合、プロパティリストのシリアライズは、オブジェクトとその状態を取得して外部化するための、柔軟で、移植性のある、適切な手段になります。ただし、このシリアライズ方式には制限があり、オブジェクトのクラス識別情報が完全には保存されず、その一般的な類別(配列、辞書、文字列など)だけが保存されます。したがって、プロパティリストから復元したオブジェクトが、元のクラスとは異なるクラスになる場合があります。このことは、オブジェクトの可変性が変化する可能性がある場合に特に問題になります。また、プロパティリストのシリアライズでは、オブジェクトの中で複数回参照されるオブジェクトは追跡されません。その結果、元のオブジェクトグラフで単独のインスタンスであったものが、シリアライズ解除の際に複数のインスタンスになる可能性があります。
Core Dataは、オブジェクトグラフを管理し、それらを永続化するためのフレームワークおよびアーキテクチャです。Core Dataのこの2番目の機能であるオブジェクトの永続化が、Core Dataを、Mementoパターンを応用したものとします。
Core Dataのアーキテクチャでは、管理対象オブジェクトコンテキストと呼ばれる中心的なオブジェクトが、アプリケーションのオブジェクトグラフにある各種のモデルオブジェクトを管理します。管理対象オブジェクトコンテキストの配下には、そのオブジェクトグラフの永続性スタックがあります。永続性スタックとは、モデルオブジェクトと外部データストア(XMLファイルやリレーショナルデータベースなど)との間で仲介を行うフレームワークオブジェクトのコレクションのことです。永続性スタックオブジェクトによって、ストア内のデータと、管理対象オブジェクトコンテキスト内の対応するオブジェクトとの間で対応付けがなされ、複数のデータストアが存在する場合には、それらのデータストアが単独の集約ストアとして管理対象オブジェクトコンテキストに提示されます。
Core DataのデザインはModel-View-Controllerおよびオブジェクトモデリングパターンの影響も強く受けています。
Core Dataはエンタープライズアプリケーションを開発する場合に特に便利です。エンタープライズアプリケーションでは、モデルオブジェクトの複雑なオブジェクトグラフを定義、管理し、データストアを対象に透過的にアーカイブおよび展開を行う必要があります。Xcodeの開発環境には、大きく分けて2種類のCore Dataアプリケーション(ドキュメントベースのものと非ドキュメントベースのもの)を作成する場合に必要となるプログラミング作業を軽減する、プロジェクトテンプレートとデザインツールが組み込まれています。また、Interface Builderアプリケーションのパレットにも、設定が可能なCore Dataフレームワークオブジェクトが組み込まれています。
参考資料: この文書の“「Cocoaのその他のアーキテクチャ」”でCore Dataの概要を説明しています。Core Dataの詳細については、『Core Data Programming Guide』を参照してください。『NSPersistentDocument Core Data Tutorial』および『Low-Level Core Data Tutorial』の各チュートリアルでは、ドキュメントベースおよび非ドキュメントベースのCore Dataアプリケーションを作成するための基本的な手順について説明しています。
オブジェクト間で1対多の依存関係を定義します。その結果、あるオブジェクトの状態が変更されたときに、それに依存するすべてのオブジェクトに変更が自動的に通知され、それらのオブジェクトが自動的に更新されるようになります。Observerパターンは、本質的には、サブジェクトとそのオブザーバが緩やかに結合している発行/引用モデルです。監視する側のオブジェクトと監視対象オブジェクトとの間では、一方が他方について十分に知らなくても、互いに通信できます。
Cocoaの通知メカニズムでは、Observerパターンに従った1対多のメッセージブロードキャストが実装されています。プログラム内のオブジェクトは、オブジェクト自身、またはほかのオブジェクトを、1つまたは複数の通知を監視するオブザーバのリストに追加します。通知はそれぞれグローバル文字列(通知名)によって識別されます。ほかのオブジェクトへの通知を行うオブジェクト(監視対象オブジェクト)では、通知オブジェクトを作成し、それを通知センターにポストします。通知センターでは、個々の通知のオブザーバを判断し、メッセージを通じてそれらのオブザーバに通知を送信します。通知によって呼び出されるメソッドは、特定の単一パラメータのシグネチャに準拠する必要があります。メソッドのパラメータは通知オブジェクトです。通知オブジェクトには、通知名、監視対象オブジェクト、任意の補足情報を含む辞書が、それぞれ格納されます。
通知のポストは同期的な手続きです。ポストする側のオブジェクトでは、通知センターからすべてのオブザーバに通知がブロードキャストされるまで、制御を取り戻すことはありません。非同期の動作が必要な場合は、通知を通知キューに置くことができます。その場合、ポストした側のオブジェクトに制御が直ちに戻り、キューに置いた通知は、キューの先頭に到達すると通知センターによってブロードキャストされます。
通常の通知、つまり、通知センターによってブロードキャストされる通知は、プロセス内に限定されます。ほかのプロセスに通知をブロードキャストする必要がある場合は、分散通知センターとその関連APIを使用できます。
通知はさまざまな用途で使用できます。たとえば、プログラム内のどこかで発生する特定のイベントに基づいて、ユーザインターフェイス要素における情報の表示方法を変更する通知をブロードキャストできます。あるいは、ドキュメントウインドウが閉じる前にドキュメント内のオブジェクトの状態を確実に保存するための手段として、通知を使用することもできます。一般に、通知の目的は、プログラムイベントをほかのオブジェクトに知らせ、それらのオブジェクトが適切に応答できるようにすることです。
しかし、通知を受信するオブジェクトが応答できるのは、イベントが発生した後のみです。この点が、委任とは大きく異なります。デリゲートには、委任元のオブジェクトによって提示された操作を拒否または変更する機会が与えられます。一方、監視を行うオブジェクトでは、進行中の操作に直接関与することはできません。
通知クラスには、NSNotification(通知オブジェクト用のクラス)、NSNotificationCenter(通知のポストとオブザーバの追加を行うクラス)、NSNotificationQueue(通知をキューに置くためのクラス)、およびNSDistributedNotificationCenterがあります。Cocoaフレームワーククラスには、任意のオブジェクトで監視することのできる通知を発行し、ポストするものが多数あります。
参考資料: 通知メカニズムとその使用に関するガイドラインの詳細については、「“通知”」を参照してください。
キー値監視は、オブジェクトの特定のプロパティが変更されたことを示す通知をほかのオブジェクトが受け取れるようにするためのメカニズムで、NSKeyValueObserving 簡易プロトコルがベースとなっています。監視対象のプロパティの候補としては、単純な属性、対一関係、または対多関係があります。Model-View-Controllerパターンのコンテキストでは、キー値監視が特に重要です。これは、キー値監視によって、ビューオブジェクトがコントローラ層を通じてモデルオブジェクト内の変更を監視できるようになるからです。そのため、キー値監視はCocoaバインディング技術にとって必要不可欠なコンポーネントです(“「コントローラクラス」”を参照)。
Cocoaでは、準拠しているすべてのオブジェクトに対してプロパティ監視機能を提供する多数のNSKeyValueObservingメソッドのデフォルト実装が“自動的に”提供されています。
キー値監視は通知メカニズムに似ていますが、重要な点で違いがあります。キー値監視では、すべてのオブザーバに変更通知を送信する中心的なオブジェクトは存在しません。代わりに、変更通知が直接、監視元のオブジェクトに送信されます。また、キー値監視は特定のオブジェクトプロパティの値に直接結び付けられています。一方、通知メカニズムは、より広範なプログラムイベントに関するものです。
キー値監視(KVO)に関与するオブジェクトは、特定の要件に準拠する必要があります(簡単に言えば、KVO準拠である必要があります)。自動監視の場合、キー値コーディングの要件に準拠する必要があり(KVC準拠)、KVC準拠のメソッド(つまり、アクセサメソッド)を使用する必要があります。キー値コーディングは、オブジェクトプロパティの値を自動的に取得および設定するための関連メカニズムです(関連する簡易プロトコルがベースとなっています)。
自動オブザーバ通知機能を無効にし、NSKeyValueObserving簡易プロトコルおよび関連するカテゴリのメソッドを使用して手動通知を実装することにより、KVOの通知を改良することができます。
参考資料: キー値監視のメカニズムおよび基盤のプロトコルの詳細については、『Key-Value Observing Programming Guide』を参照してください。また、関連文書の『Key-Value Coding Programming Guide』および『Cocoa Bindings Programming Topics』も参照してください。
別のオブジェクトへのアクセスを制御する代理またはプレースホルダを提供します。このパターンを使用して、別のオブジェクト(リモートオブジェクト、作成にコストがかかるオブジェクト、安全を保つ必要があるオブジェクトなど)へのアクセスを制御する代理オブジェクトを作成できます。このパターンの構造はDecoratorパターンに似ていますが、目的が異なります。Decoratorがオブジェクトに動作を追加するのに対し、Proxyはオブジェクトへのアクセスを制御します。
NSProxyクラスは、ほかのオブジェクト(まだ存在していない場合も可)に対するプレースホルダまたは代理として機能するオブジェクトのためのインターフェイスを定義します。通常、代理オブジェクトは自身に送信されたメッセージを、それが成り代わっているオブジェクトに転送しますが、そのオブジェクトをロードしたり、自身をそのオブジェクトに変換したりすることによって、メッセージに応答することもできます。NSProxyは抽象クラスですが、ルートオブジェクトが備えていると想定されているNSObjectプロトコル、およびその他の基本的なメソッドを実装しています。実際、このクラスはNSObjectクラスと同じように、階層におけるルートクラスです。
NSProxyの具象サブクラスは、処理コストのかかるオブジェクトの遅延インスタンス化や、セキュリティのための見張りオブジェクトとしての機能など、Proxyパターンで説明されている目的を達成することができます。FoundationフレームワークにあるNSProxyの具象サブクラスであるNSDistantObjectは、透過的な分散メッセージング用のリモートプロキシを実装しています。NSDistantObjectオブジェクトは分散オブジェクトのためのアーキテクチャの一部です。このオブジェクトは、ほかのプロセスやスレッドにあるオブジェクトの代理として機能することによって、それらのプロセスやスレッド内のオブジェクトどうしのやり取りを可能にします。
Commandパターンの応用であるNSInvocationオブジェクトもまた、分散オブジェクトアーキテクチャの一部です(“「呼び出しオブジェクト」”を参照)。
Cocoaでは、NSProxyオブジェクトは分散オブジェクトでのみ利用します。NSProxyオブジェクトは、具体的にはNSDistantObjectおよびNSProtocolCheckerの各具象サブクラスのインスタンスです。分散オブジェクトは、プロセス間メッセージング(同じコンピュータ内または異なるコンピュータ間)に使用できるだけでなく、分散コンピューティングや並列処理の実装にも使用できます。処理コストのかかるリソースの作成やセキュリティの確保など、ほかの目的のためにプロキシオブジェクトを使用する必要がある場合は、NSProxyの具象サブクラスを独自に実装する必要があります。
クラスのインスタンスが1つだけであることを保証し、そのインスタンスへのグローバルなアクセスポイントを提供します。クラスは、自身の唯一のインスタンスを追跡し、ほかのインスタンスを作成できないようにします。Singletonクラスは、グローバルなリソースへのアクセスを単独のオブジェクトを通じて提供することが有用な場合に適しています。
Cocoaフレームワーククラスのいくつかはシングルトンです。たとえば、NSFileManager、NSWorkspace、NSApplicationなどがあります。1つのプロセスでは、これらのクラスのインスタンスが1つに制限されます。クライアントがクラスに対してインスタンスを要求すると、共有のインスタンスが返されます。このインスタンスは最初の要求時に遅延作成されます。
シングルトンクラスから返される共有インスタンスと、シングルトンではないクラスのインスタンスの使いかたに違いはありません。ただし、シングルトンクラスのインスタンスはコピー、保持、または解放ができません(関連するメソッドはNULL操作として実装しなおされます)。状況によっては、シングルトンクラスを独自に作成することもできます。
参考資料: シングルトンクラスの作成方法の詳細については、“「Cocoaオブジェクト」”を参照してください。
ある操作におけるアルゴリズムの骨組みを定義し、手順の一部をサブクラスに任せます。テンプレートメソッドパターンによって、サブクラスでは、アルゴリズムの構造を変えずにアルゴリズムの特定の手順を定義しなおせるようになります。
Template MethodパターンはCocoaの基礎的なデザインであり、一般的にも、オブジェクト指向フレームワークの基礎的なデザインになっています。Cocoaのパターンでは、プログラムのカスタムコンポーネントがアルゴリズムに自身をフックすることができますが、それらのカスタムコンポーネントがいつ、どのように必要になるかはフレームワークコンポーネントによって決まります。多くの場合、Cocoaのクラスのプログラムインターフェイスには、サブクラスによるオーバーライドを前提としたメソッドが含まれています。これらのいわば汎用メソッドは、実行時に、フレームワークが実行している処理の特定の時点で、フレームワークによって呼び出されます。これらの汎用メソッドによって、カスタムコードのための構造が提供され、フレームワーククラスによって実行および調整される処理に対して、プログラム固有の動作やデータを提供できるようになります。
CocoaにおけるTemplate Methodパターンの応用を利用するには、サブクラスを作成し、フレームワークから呼び出される、アプリケーションが実行しているアルゴリズムにアプリケーション固有の入力を挿入するメソッドをオーバーライドする必要があります。フレームワークを独自に開発する場合は、デザインにこのパターンをおそらく含める必要があります。
注: CocoaにおけるTemplate Methodパターンの応用の詳細については、“「Cocoaプログラムへの動作の追加」”を参照してください(特に、“「Cocoaクラスからの継承」”を参照してください)。
Cocoaのドキュメントアーキテクチャは、Template Methodパターンの応用としての、オーバーライドを前提とするフレームワークメソッドの汎用的なデザインの特化した(かつ重要な)例です。複数のドキュメントをそれぞれ独自のウインドウで作成し管理することのできるCocoaアプリケーションは、ほとんどすべてがドキュメントアーキテクチャをベースとしています。このアーキテクチャには、NSDocument、NSWindowController、およびNSDocumentControllerという、互いに連携して動作する3つのフレームワーククラスのオブジェクトがあります。NSDocumentオブジェクトは、ドキュメントのデータを表すモデルオブジェクトを管理します。このオブジェクトは、ユーザからの要求が発生すると、ドキュメントのデータをファイルに書き込み、データを再ロードして、そのデータを使用してモデルオブジェクトを作成しなおします。NSWIndowControllerオブジェクトは、特定のドキュメントのユーザインターフェイスを管理します。ドキュメントベースアプリケーションのNSDocumentControllerオブジェクトは、開かれているすべてのドキュメントを追跡、管理します。また、それ以外に、アプリケーションの動作の調整を行います。実行時には、これらのオブジェクトはそれぞれ、特定の操作を実行するよう要求するメッセージをApplication Kitから受け取ります。アプリケーションの開発者は、アプリケーション固有の動作を追加するために、これらのメッセージによって呼び出されるメソッドの多くをオーバーライドする必要があります。
CocoaのドキュメントアーキテクチャのデザインはModel-View-Controllerパターンの影響も強く受けています。
ドキュメントベースのCocoaアプリケーション用のプロジェクトを作成するには、Xcodeの「新規プロジェクト」アシスタントで「Cocoa Document-based Application」テンプレートを選びます。次に、NSDocumentのカスタムサブクラスを実装する必要があります。また、NSWindowControllerおよびNSDocumentControllerのカスタムサブクラスを実装することもできます。Application Kitには、アプリケーションのドキュメント管理ロジックのほとんどがあらかじめ用意されています。
注: この文書の“「Cocoaのその他のアーキテクチャ」”でドキュメントアーキテクチャの概要を説明しています。Template Methodパターンの応用であるこのドキュメントアーキテクチャの詳細については、『Document-Based Applications Overview』を参照してください。
| < 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 |