'아이폰개발' 카테고리의 다른 글
[아이폰개발] IB없이 HTTP통신 예제 (0) | 2011.02.25 |
---|---|
[아이폰개발] 메세징 원리 라이브러리 미번역 (0) | 2011.02.10 |
[아이폰개발] 탭바 인터페이스 라이브러리 번역 (0) | 2011.02.10 |
[아이폰개발] hpple 사용예 (0) | 2011.01.28 |
[아이폰개발] 오브젝트별 참고사이트 (0) | 2011.01.21 |
[아이폰개발] IB없이 HTTP통신 예제 (0) | 2011.02.25 |
---|---|
[아이폰개발] 메세징 원리 라이브러리 미번역 (0) | 2011.02.10 |
[아이폰개발] 탭바 인터페이스 라이브러리 번역 (0) | 2011.02.10 |
[아이폰개발] hpple 사용예 (0) | 2011.01.28 |
[아이폰개발] 오브젝트별 참고사이트 (0) | 2011.01.21 |
Objective-C では、メッセージは実行時までメソッド実装にバインドされません。コンパイラは、次のメッセージ式を変換します。
|
上記のメッセージは、メッセージ関数の呼び出し objc_msgSend
に変換されます。この関数は、メッセージに記述されたレシーバ とメソッドの名前(メソッドセレクタ)を 2 つの主要なパラメータとして利用します。
|
メッセージに渡された引数は、objc_msgSend
にも渡されます。
|
メッセージング関数は、動的バインディングに必要なことをすべて実行します。
注意:メッセージング関数の呼び出しは、コンパイラによって生成されます。自分が作成するコードの中で直接呼び出してはなりません。 |
メッセージングのポイントは、コンパイラが各クラスとオブジェクトに対して構築する構造にあります。あらゆるクラス構造には、次の2つの重要な要素が含まれています。
setOrigin::
メソッドのセレクタは setOrigin::
(を実装するプロシージャ)のアドレスと関連付けられ、display
メソッドのセレクタは display
のアドレスと関連付けられています。新しいオブジェクトが作成されると、そのメモリが割り当てられ、そのインスタンス変数が初期化されます。オブジェクトの変数の中で最初のものはクラス構造のポインタです。このポインタは isa
と呼ばれ、クラス、および継承されるすべてのクラスにアクセスする手段をオブジェクトに提供します。
これらのクラスとオブジェクト構造の要素を、図 2-5 に示します。
図 2-5 メッセージングフレームワーク
メッセージをオブジェクトに送信すると、メッセージング関数は、オブジェクトの isa
ポインタをたどってクラス構造に到達し、そこでディスパッチテーブルでメソッドセレクタを調べます。ディスパッチテーブルにセレクタが見つからない場合、objc_msgSend
はポインタをたどってスーパークラスに到達し、そのディスパッチテーブルの中でセレクタを探します。失敗し続けると、objc_msgSend
は NSObject クラスに達するまでクラス階層を遡ることになります。セレクタが見つけると、この関数はテーブルに含まれているメソッドを呼び出し、受信側オブジェクトのデータ構造を渡します。
これが、実行時にメソッド実装が選択される方法です。オブジェクト指向プログラミング特有の言い回しをすれば、メソッドがメッセージへ動的にバインドされるといいます。
メッセージング処理をスピードアップするため、ランタイムシステムはセレクタの使用に伴って、セレクタと、対応するメソッドのアドレスをキャッシュします。クラスごとに個別のキャッシュがあり、クラスで定義したメソッドのセレクタだけでなく、継承したメソッドのセレクタを含むこともできます。ディスパッチテーブルを検索する前に、メッセージングルーチンはまず、受信側オブジェクトのクラスのキャッシュを確認します(一度使用したメソッドは再度使用する可能性があるため)。キャッシュにメソッドセレクタがある場合、メッセージングは関数呼び出しより若干遅いだけです。キャッシュを「ウォームアップ」するのに十分な時間、プログラムが実行されると、そのプログラムが送信するほとんどすべてのメッセージは、対応するキャッシュされたメソッドが見つかります。プログラムの実行に伴い、新しいメッセージに対応するため、キャッシュは動的に成長します。
セレクタ
隠し引数
self と super に対するメッセージ
効率化のため、コンパイル済みのコードでは完全な ASCII 名をメソッドセレクタとして使用しません。その代わりに、コンパイラは各メソッド名をテーブルに書き込み、その名前を実行時にメソッドを示す一意の識別子と組み合わせます。ランタイムシステムによって、各識別子が一意であることが保証されます。2 つのセレクタが同じであることはなく、同じ名前のメソッドはすべて同じセレクタに対応します。コンパイル済みのセレクタは、他のデータと区別するため、特別な型 SEL
に割り当てられます。有効なセレクタは 0 であることはありません。メソッドへの SEL
識別子の割り当てはシステムに任せる必要があります。任意に割り当てても無駄になります。
@selector()
ディレクティブにより、Objective-C のソースコードは完全なメソッド名ではなく、コンパイル済みのセレクタを参照することができます。次の例では、setWidth:height:
のセレクタを、setWidthHeight
変数に代入しています。
|
コンパイル時に @selector()
ディレクティブを使用して、SEL
変数に値を代入するのが最も効率的です。しかし、場合によっては、プログラムで実行時に文字列をセレクタに変換する必要があります。これを実行するには、NSSelectorFromString
関数を使います。
|
逆方向の変換も可能です。NSStringFromSelector
関数はセレクタに対応するメソッド名を返します。
|
このようなランタイム関数については、Cocoa フレームワークリファレンスドキュメントで説明しています。
コンパイル済みのセレクタは、メソッド実装ではなく、メソッド名を識別します。たとえば、Rectangle の display
メソッドには、他のクラスで定義された display
メソッドと同じセレクタが対応します。これはポリモーフィズム(多態性)と動的バインディングには不可欠です。これにより、さまざまなクラスに属するレシーバに、同じメッセージを送信することができます。メソッド実装ごとに 1 つのセレクタがあったとしたら、メッセージは関数呼び出しと変わりません。
クラスメソッドと同じ名前のインスタンスメソッドは、同じセレクタに割り当てられます。しかし、それらは別々のドメインに属するため、2 つの間に混乱はありません。クラスでは、display
インスタンスメソッドに加えて、display
クラスメソッドを定義することができます。
メッセージングルーチンはセレクタを通してのみメソッド実装にアクセスできるため、同じセレクタに対応するすべてのメソッドを同等に扱います。ルーチンは、セレクタに基づいてメソッドの戻り型と引数のデータ型を知ります。したがって、静的に型定義されたレシーバに送信されたメッセージを除いて、動的バインディングでは、同じ名前を持つメソッドのすべての実装で、戻り型と引数型が同じである必要があります(コンパイラはクラス型からメソッド実装を知ることができるため、静的に型定義されたレシーバはこのルールの例外です)。
同じ名前のクラスメソッドとインスタンスメソッドは、同じセレクタで表されますが、引数と戻り型が異なる可能性があります。
performSelector:
、performSelector:withObject:
、および performSelector:withObject:withObject:
メソッドは NSObject プロトコルで定義されており、SEL
識別子を初期引数として利用します。3 つのメソッドはすべて、メッセージング関数に直接マップされます。たとえば、次のように記述します。
|
次のように記述しても同じです。
|
これらのメソッドにより、メッセージを受信するオブジェクトを変更できるのと同じように、実行時にメッセージを変更できます。メッセージ式を構成する両方の要素に変数名を使用することができます。
|
上記の例では、レシーバ(helper
)は実行時に(架空の getTheReceiver
関数によって)選択され、レシーバが実行するように要求されるメソッド(request
)も実行時に(同様に架空の getTheSelector
関数によって)決められます。
注意:performSelector: とその関連メソッドは id を返します。実行されるメソッドが別の型を返す場合は、適切な型にキャストする必要があります(ただし、キャストがすべての型に有効なわけではありません。メソッドはポインタまたはポインタと互換性のある型を返す必要があります)。 |
ユーザインタフェース制御の処理において、Application Kit はレシーバとメッセージの両方を変更する方法を有効に利用しています。
NSControls は、アプリケーションへの指示を指定するのに使用できるグラフィカルデバイスです。大部分はボタン、スイッチ、ノブ、テキストフィールド、ダイヤル、メニュー項目など、現実世界の制御デバイスに似ています。ソフトウェアでは、これらのデバイスがアプリケーションとユーザの間に介在します。これらのデバイスは、キーボードやマウスなどのハードウェアデバイスから発されるイベントを解釈し、アプリケーション固有の命令に変換します。たとえば、「検索」というラベルの付いたボタンはマウスクリックを、アプリケーションが何かの検索を開始する命令に変換します。
Application Kit は制御デバイスを作成するためのテンプレートを定義し、「そのまま」使用できる独自のデバイスもいくつか定義します。たとえば、NSButtonCell クラスでは、NSMatrix に割り当てて、サイズ、ラベル、ピクチャ、フォント、およびキーボードショートカットを初期化できるオブジェクトを定義します。ユーザがボタンをクリックすると(あるいは、キーボードショートカットを使用すると)、NSButtonCell はアプリケーションに何かを実行するよう指示するメッセージを送信します。これを行うには、NSButtonCell を画像、サイズ、およびラベルだけでなく、どんなメッセージを送信し、誰に送信するかに関する指示においても初期化する必要があります。したがって、NSButtonCell はアクションメッセージ、送信するメッセージで使用するメソッドセレクタ、ターゲット(メッセージを受信するオブジェクト)で初期化することができます。
|
NSButtonCell は、NSObject の performSelector:withObject:
メソッドを使用してメッセージを送信します。すべてのアクションメッセージは 1 つの引数、つまりメッセージを送信する制御デバイスの id
を受け取ります。
Objective-C でメッセージを変更できないとしたら、すべての NSButtonCells が同じメッセージを送信しなければならなず、メソッドの名前が NSButtonCell ソースコードで固定されます。ユーザ操作をアクションメッセージに変換するメカニズムを単に実装するのではなく、NSButtonCell などのコントロールでメッセージの内容に制約を課す必要が生じます。これでは、どのようなオブジェクトも、複数の NSButtonCell に対応するのが困難になります。ボタンごとに 1 つのターゲットを用意するか、ターゲットオブジェクトがメッセージを送信したボタンを検出し、それに応じて動作する必要が生じます。ユーザインタフェースを再配置するたびに、アクションメッセージに応答するメソッドも再実装する必要が生じます。幸いにも、Objective-C では、このように不要な複雑さが回避されています。
オブジェクトが、レパートリーにないメソッドを実行するメッセージを受信すると、エラーが発生します。これは、存在しない関数を呼び出した場合と同じ種類のエラーです。しかし、メッセージングは実行時に行われるため、多くの場合、プログラムを実行するまでエラーが明らかになりません。
メッセージセレクタが不変で、受信側オブジェクトのクラスが分かっている場合、このようなエラーを回避するのは比較的簡単です。プログラムを記述するときに、レシーバが応答できることを確認しておけばよいからです。レシーバが静的に型定義されていれば、コンパイラがそのテストを実行してくれます。
しかし、メッセージセレクタまたはレシーバのクラスが可変の場合、そのテストを実行時まで延期しなければならない場合もあります。NSObject クラスで定義されている respondsToSelector:
メソッドを使用してレシーバがメッセージに応答できるかどうかを調べることができます。引数としてメソッドセレクタを受け取り、レシーバがセレクタに一致するメソッドにアクセスできるかどうかを返します。
|
respondsToSelector:
テストが特に重要なのは、コンパイル時に制御の及ぶ範囲内にないオブジェクトにメッセージを送信する場合です。たとえば、他から設定可能な変数によって指定されるオブジェクトにメッセージを送信するコードを記述する場合は、必ずメッセージに応答できるメソッドをレシーバが実装するようにします。
注意:また、オブジェクトは、自身で直接応答できない場合、受信したメッセージを他のオブジェクトに転送するように準備することもできます。その場合、メッセージを別のオブジェクトに割り当てて間接的に応答しているにも関わらず、オブジェクトがメッセージを処理できるように見えます。詳細については、「転送」を参照してください。 |
メッセージング関数はメソッドを実装するプロシージャを見つけると、そのプロシージャを呼び出し、メッセージのすべての引数を渡します。また、次の 2 つの隠し引数をプロシージャに渡します。
これらの引数はすべてのメソッド実装に、当該実装を呼び出したメッセージ式の両方の構成要素に関する明確な情報を提供します。それらの引数は、メソッドを定義するソースコードで宣言されないため、「隠し」引数と呼ばれています。これらは、コードのコンパイル時に実装に挿入されます。
これらの引数は明示的には宣言されませんが、ソースコードは(受信側オブジェクトのインスタンス変数を参照できるのと同じように)隠し引数を参照することができます。メソッドは受信側オブジェクトを self
として、自身のセレクタを _cmd
として参照します。次の例では、_cmd
は strange
メソッドのセレクタを参照し、self
は strange
メッセージを受信するオブジェクトを参照します。
|
この 2 つの引数のうち、self
のほうが有用です。実際、これは受信側オブジェクトのインスタンス変数を、メソッド定義で利用可能にする方法です。
self
と super
に対するメッセージObjective-C では、メソッドを実行するオブジェクトを参照するためにメソッド定義内で使用できる 2 つのキーワード、self
と super
が提供されています。
たとえば、操作対象となるすべてのオブジェクトの座標を変更する必要がある、reposition
メソッドを定義するとします。そのメソッドは、変更を行う setOrigin::
メソッドを呼び出すことができます。必要なのは、reposition
メッセージ自体の送信先となった同じオブジェクトに、setOrigin::
メッセージを送信することだけです。位置変更コードを記述する際には、そのオブジェクトを self
または super
のいずれかとして参照することができます。reposition
メソッドはどちらも読み取ることができます。
|
または
|
この場合、どのようなオブジェクトであっても、self
と super
はどちらも reposition
メッセージを受信するオブジェクトを参照します。ただし、この 2 つのキーワードはまったく異なるものです。self
は、メッセージングルーチンがすべてのメソッドに渡す隠し引数の 1 つであり、インスタンス変数の名前と同じように、メソッド実装内で自由に使用できるローカル変数です。super
は、メッセージ式でレシーバとしてのみ self
の代わりに使用できるキーワードです。レシーバーから見ると、2 つのキーワードは、主にメッセージング処理に与える影響が異なります。
self
は受信側オブジェクトのクラスのディスパッチテーブルから始まり、通常の方法でメソッド実装を検索します。上記の例では、再配置メッセージを受信するオブジェクトのクラスから検索を始めます。super
は、まったく異なる場所でメソッド実装の検索を開始します。検索は、super
が出現するメソッドを定義する、クラスのスーパークラスから始まります。上記の例では、再配置が定義されるクラスのスーパークラスから検索を始めます。どこで super
がメッセージを受信しても、コンパイラは objc_msgSend
関数の代わりに別のメッセージングルーチンを使用します。代替ルーチンは、メッセージを受信するオブジェクトのクラスではなく、定義クラスのスーパークラス、つまり super
にメッセージを送信するクラスのスーパークラスを直接参照します。
self
と super
の違いは、3 つのクラスの階層で明確になります。たとえば、Low というクラスに属するオブジェクトを作成するとします。Low のスーパークラスは Mid で、Mid のスーパークラスは High です。3 つのクラスすべてで negotiate
というメソッドを定義し、さまざまな用途に使用します。さらに、Mid では makeLastingPeace
という高度なメソッドを定義しますが、これは negotiate
メソッドも必要とします。次の図 2-6 にこれを図示します。
図 2-6 High、Mid、Low
ここで、makeLastingPeace
メソッドを実行するために Low オブジェクトにメッセージを送信します。すると、makeLastingPeace
は同じ Low オブジェクトに negotiate
メッセージを送信します。ソースコードの中でメッセージの送信対象オブジェクトを self
と呼ぶ場合には、次のようになります。
|
メッセージングルーチンは、self
の実際のクラスである Low に定義されているバージョンの negotiate
を探します。しかし、Mid のソースコードで送信対象のオブジェクトを super
と呼ぶ場合には、次のようになります。
|
メッセージングルーチンは、High に定義されているバージョンの negotiate
を探します。makeLastingPeace
は Mid で定義されているため、メッセージングルーチンは受信側オブジェクトのクラス (Low) を無視して、Mid のスーパークラスにスキップします。どちらのメッセージも、Mid バージョンの negotiate
を探しません。
この例に示すように、super
は別のメソッドをオーバーライドするメソッドをバイパスする手段を提供します。この場合は、makeLastingPeace
が、元の High バージョンの negotiate
を再定義する Mid バージョンを無視することを可能にしました。
Mid バージョンの negotiate
に到達できないのは欠陥のように見えるかもしれませんが、このような状況ではそれを回避するほうが適切です。
negotiate
をオーバーライドして、Low クラス(およびそのサブクラス)のインスタンスが、再定義されたバージョンのメソッドを代わりに呼び出すようにしています。Low の設計者は、Low オブジェクトに継承メソッドを実行させないようにしたわけです。super
にメッセージを送信することで、Mid の makeLastingPeace
メソッドの作成者は、Mid バージョンの negotiate
(および Mid を継承する Low などのクラスで定義するバージョン)を意図的にスキップして、High クラスに定義されているバージョンを実行するようにしました。Mid の設計者は、negotiate
の High バージョンだけを使用するようにしたいわけです。それでも Mid バージョンの negotiate
を使用することはできますが、そのためには Mid インスタンスに直接メッセージを送信する必要があります。
super
へのメッセージにより、メソッド実装を複数のクラスに分散することができます。既存のメソッドをオーバーライドして変更や追加を行う一方で、元のメソッドをその変更に組む込むことができます。
|
処理によっては、継承階層の各クラスで作業の一部を行い、残りの作業についてはメッセージを super
に渡して処理するメソッドを実装することができます。新たに割り当てられたインスタンスを初期化する init
メソッドは、このように動作するように設計されています。それぞれの init
メソッドは、クラスに定義されているインスタンス変数を初期化する 役割を持っています。しかし、初期化の前に、init
メッセージを super
に送信して、継承元のクラスにインスタンス変数を初期化させます。init
の各バージョンがこの手続きに従うため、クラスは継承の順序に従ってインスタンス変数を初期化することになります。
|
また、中核的な機能をスーパークラスに定義する 1 つのメソッドに集中させ、サブクラスにおいて super
へのメッセージを使用してそのメソッドを組み込むこともできます。たとえば、インスタンスを作成するすべてのクラスメソッドは、新しいオブジェクトにデータ記憶域を割り当て、isa
ポインタをクラス構造で初期化する必要があります。これは、通常、NSObject クラスに定義されている alloc
および allocWithZone:
メソッドに委ねられます。別のクラスでこれらのメソッドをオーバーライドする場合も(まれなケース)、そのメソッドでメッセージを super
に送信することによって基本機能を利用することができます。
super
は実行するメソッドの検索を始める場所をコンパイラに伝える単なるフラグで、メッセージのレシーバとしてのみ使用します。しかし、self
は変数名で、いろいろな方法で使用でき、新しい値を代入することもできます。
クラスメソッドの定義では、まさにそうすることがよくあります。クラスメソッドは多くの場合、クラスオブジェクトではなく、クラスのインスタンスを対象としています。たとえば、多くのクラスメソッドがインスタンスの割り当てと初期化を結合し、多くの場合、同時にインスタンス変数値も設定します。このようなメソッドでは、インスタンスメソッドの場合と同様に、新たに割り当てられたインスタンスにメッセージを送信して、self
インスタンスを呼び出すことも考えられます。しかし、これはエラーになります。self
と super
は、どちらも受信側オブジェクト(メソッドを実行するように指示するメッセージを取得するオブジェクト)を参照します。インスタンスメソッド内では self
はインスタンスを参照しますが、クラスメソッド内では self
はクラスオブジェクトを参照します。次の例は、してはいけないことを示します。
|
混乱を避けるために、通常はクラスメソッド内のインスタンスを参照するとき、self
ではなく、変数を使用するほうが適切です。
|
実際、クラスメソッドの中で self
に alloc
メッセージを送信するよりも、多くの場合は alloc
を [self class]
に送信するほうが有効です。こうしておけば、クラスをサブクラス化し、サブクラスが rectangleOfColor:
メッセージを受信した場合、返されるインスタンスはそのサブクラスと同じ型になります。
|
オブジェクト割り当ての詳細については、「メモリ管理」を参照してください。
[아이폰개발] IB없이 HTTP통신 예제 (0) | 2011.02.25 |
---|---|
[아이폰개발] 참고 사이트 (0) | 2011.02.16 |
[아이폰개발] 탭바 인터페이스 라이브러리 번역 (0) | 2011.02.10 |
[아이폰개발] hpple 사용예 (0) | 2011.01.28 |
[아이폰개발] 오브젝트별 참고사이트 (0) | 2011.01.21 |
Tab Bar Controller
u Tab Bar인터페이스
n 용도
같은 데이터셋에대해 다른 표현방법을 제공해야할 경우
기능별로 나누어서 어플리케이션을 구성해야할 경우
n Tab Bar View 컨포넌트
화면 하단에 표시
어플리케이션의 각종 모드간의 화면 전환기능을 지원
각 모드의 상태에 관한 정보를 표시가능
n Tab Bar ViewController 오브젝트
Tab Bar View를 작성하고 관리
각 모드별 뷰를 관리하는 커스텀뷰컨트롤러를 관리
n Tab Bar View는 통상의 커스터마이즈 가능한 오브젝트이나 Tab Bar인터페이스에 포함된경우에는 변경해서는 안됨
Tab Bar인터페이스에서는 Tab Bar뷰가 Tab Bar컨트롤러에 소유된 프라이베이트한 뷰계층의 일부로 간주함
액티브한 탭 리스트의 변경이 필요한때에는 반드시 Tab Bar컨트롤러의 메소드를 사용해야함
u Tab Bar인터페이스의 오브젝트
n 종류
UITabBarController 오브젝트
탭별 한개씩 존재하는 커스텀 ViewController 오브젝트
옵션의 델리게이트 오브젝트
n 설명
각 뷰컨트롤러에는 선택될때 표시되는 컨텐츠가 지정되어 있음
지정되는 뷰컨트롤러에는 단일 뷰를 표시하는 커스텀 뷰 컨트롤러나 네비게이션 컨트롤러도 사용가능. 하지만 탭바뷰컨트롤러는 사용 불가능
뷰컨트롤러 프로퍼티에 5개가 넘는 항목을 추가하면 탭바에 들어가지 못한 항목의 표시를 위해
특별한 뷰컨트롤러(「More」View Controller)를 자동적으로 삽입
n 「More」View Controller
5개이상의 뷰컨트롤러를 테이블형식으로 표시가능
커스터마이즈 하거나 선택하는건 불가능
탭바 컨트롤러가 관리하는 뷰 컨트롤러 리스트에 포함되어있지 않음
보통 필요한때에 자동으로 표시되어 커스텀콘텐츠로부터 독립되어있음
참조가 필요할 경우에는UITabBarController의moreNavigationController 프로퍼티에 접근
u Tab Bar 인터페이스의 작성
n 인터페이스 사용방법 결정
어플리케이션의 메인 윈도우에 직접 추가
Split view 인터페이스의 두개중 한개의 루트뷰중 한곳에 추가(iPad만 가능)
모드에 고유의 구성을 필요로하는 데이터를 표시하기위해 모달모드로 표시
Popover에서 표시(iPad만 가능)
n 주의사항
네비게이션 컨트롤러를 탭내에 내장하는것은 가능하나 그 반대의 경우는 불가능
n 탭바 인터페이스용의 커스텀 뷰 컨트롤러의 정의
탭바 인터페이스의 각 모드는 다른 모드들과는 독립되어 있음
각모드의 루트 컨트롤러가 탭 안의 콘텐츠를 정의하고 있음
모드의 콘텐츠가 복잡한 경우에는 네비게이션 컨트롤러를 인스톨함으로서 탭내에서의
조작을 지원
모드의 콘텐츠가 비교적 단순한 경우에는 단일뷰를 가진 커스텀 뷰 컨트롤러를 인스톨
n NIB파일을 사용한 탭바 인터페이스의 작성
탭바컨트롤러를 nib파일에서 로드하는 경우는 커스텀 뷰 컨트롤러에서 로드하는 경우와 조금 다름
뷰컨트롤러의 경우 프로그램안에서 작성하는 경우나 다른 nib파일에서 로드하는 경우 똑같이 개별적으로 작성함
탭바 컨트롤러의 경우 뷰는 반드시 프로그램안에서 작성하기때문에 독립된 nib파일에 격납할 뷰는
존재하지 않기때문에 탭바컨트롤러가 nib파일을 관리할 일이 없음
대신에 탭바컨트롤러와 nib파일이 관계를 가지는 경우는 탭바컨트롤러 자체가 nib파일에
포함될 경우
그렇기 때문에 대부분의 경우에 탭바컨트롤러는 다른 오브젝트가 관리하는 닙파일에 포함됨
가장 이상적인 구성은 탭뷰컨트롤러를 어플리케이션의 메인nib파일에 포함시키는 것
탭바 컨트롤러 자신이 어플리케이션 윈도우의 메인뷰를 제공하는 경우 모달 모드에서 표시 되는
탭바 컨트롤러를 nib파일에서 로드하는것도 가능하지만 최적은 아님
실제로는 탭바컨트롤러를 필요할때 프로그램안에서 작성해서 쓰는게 일반적
위 그림에서 각 커스텀 뷰 컨트롤러는 한개의 탭에 연결된 루트 뷰 컨트롤러를 표시함
각 뷰컨트롤러는 커스텀 뷰 컨트롤러이기때문에 뷰를 포함하고 있는 nib파일을 참조하고 있음
메인nib파일에 각각의 커스텀 뷰를 포함시키는것도 가능하지만 추천하지 않음
뷰를 별도의 nib파일에 포함시키는것으로 시스템에서 필요에따라 뷰를 메모리에서
완전히 파기하는게 가능해짐
n 텝바컨트롤러의 작성 순서 예(메인 윈도우 nib에 포함시킬경우)
탭바 어플리케이션 템플리트를 사용할경우 1,2과정은 스킵
1. 탭바컨트롤러 오브젝트를 라이브러리에서 인터페이스 빌더의 도큐멘트윈도우에 드래그함
탭바컨트롤러를 nib파일에 추가하면 인터페이스 빌더에 의해 1개의 탭바뷰, 2개의 루트뷰컨트롤러, 2개의 탭바아이콘이 추가됨
2. 아웃렛을 사용해서 탭바컨트롤러에의 참조를 저장함
실행시에 이 탭바컨트롤러에 엑세스하기위해선 아웃렛을 사용하거나 닙파일을 로드할때 닙파일의 최상위 레벨의 오브젝트를 명시적으로 취하는 방법이 있음
일반적으로 아웃렛을 사용
아웃렛을 추가하는 방법
@interface MyAppDelegate :NSObject <UIApplicationDelegate> {
IBOutlet UITabBarController* myTabBarController;
}
@end
아웃렛의 정의를 추가하고 아웃렛에서 탭바컨트롤러오브젝트에 접속을 작성
3. 인터페이스에 표시하고싶은 탭수에 맞춰서 뷰컨트롤러를 추가하거나 삭제함
탭바 컨트롤러 오브젝트에 포함된 뷰컨트롤러 수에 의해 탭바 인터페이스에 표시되는 탭의 수가 정해짐
최종적인 탭바컨트롤러에는 최소한 2개의 뷰컨트롤러가 포함되야함
인터페이스 빌더의 라이브러리에서 뷰컨트롤러나 네비게이션컨트롤러 테이블뷰컨트롤러를 드래그해서 탭과 연결시키는것이 가능함
뷰컨트롤러를 추가하는 방법은 아래와 같음
■ 적절한 오브젝트를 라이브러리에서 편집서페이스내의 탭바에 드래그함
■ 오브젝트 라이브러리에서 인터페이스 빌더의 도큐먼트윈도우안의 탭바 컨트롤러에 드래그
윈도우는 아웃라인모드 이여야함
네비게이션 컨트롤러나 테이블뷰 컨트롤러를 인터페이스에 추가할 경우에는 해당 오브젝트를 라이브러리에서 드래그하거나 탭바 컨트롤러를 선택해서「Attributes」인스펙터를 사용해서 뷰컨트롤러의 종류를 설정
범용 뷰컨트롤러 오브젝트를 닙파일에 드래그해서 클래스명을 원하는 클래스타입으로 변경
4. 화면에 표시할 순서대로 뷰컨트롤러를 정렬
탭바 컨트롤러의 편집서페이스에 표시된 탭을 드래그하거나 인터페이스빌더의 도큐먼트윈도우에 뷰컨트롤러를 드래그함으로서 (아웃라인모드인 경우) 뷰컨트롤러의 순서를 바꾸는것이 가능함
편집서페이스에는 모든 탭이 표시되나 실행시에는 5개만 표시됨
탭바 컨트롤러에 6개이상의 뷰컨트롤러가 포함된 경우에는 초기화상태의 탭바에는 최초의 4개만 표시됨 5번째의 탭에는 나머지 뷰컨트롤러를 표시하는「More」뷰컨트롤러용으로 예약됨
5. 각 탭에 루트뷰컨트롤러를 설정
각 루트뷰컨트롤러에는 다음과같은 속성을 설정해야만함
■ 「Identity」인스펙터를 사용해서 임의의 뷰컨트롤러 오브젝트의 클래스를 설정함
루트뷰컨트롤러가 범용의 뷰컨트롤러오브젝트이거나 테이블뷰컨트롤러오브젝트인 경우에는 클래스명을 커스텀서브클래스로 변경가능
루트뷰컨트롤러가 네비게이션 컨트롤러 오브젝트인경우에는 클래스명을 변경해서는 안됨
■ 뷰컨트롤러에 뷰를 설정
가장 일반적으로 뷰컨트롤러의 닙네임속성을 뷰를 포함한 닙파일의 이름으로 설정하는 방법이 사용
뷰를 메인 닙파일에 포함시키는것도 가능은 하나 추천하지 않음
■ 필요에 따라서 뷰컨트롤러의 스타일을 설정함
루트뷰컨트롤러중 네비게이션컨트롤러를 사용할 경우에는
6. 각뷰컨트롤러에 탭바 아이템을 설정
탭바컨트롤러의 편집서페이스 혹은 인터페이스 빌더의 도큐먼트윈도우(아웃라인모드 혹인 브라우져모드의 경우)에서 탭바이이템을 선택가능함 인터페이스빌더를 사용해서 탭바아이템의 타이틀, 화상, 뱃지를 설정할수 있음
혹은 「Attributes」인스펙터로 Identifier프로퍼티의 값을 할당함으로 탭바아이템을 표준의 시스템탭 한개에 설정하는것도 가능
7. 어플리케이션 델리게이트의applicationDidFinishLaunching메소드안에서 탭바컨트롤러뷰를 메인윈도우에 추가함
탭바 컨트롤러를 자동으로 어플리케이션의 윈도우에 인스톨하는것은 불가능 아래의 코드로 직접인스톨해야함
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window addSubview:myTabBarController.view];
}
8. 닙파일을 저장
n 프로그램으로 탭바인터페이스를 작성
탭바컨트롤러를 프로그램안에 작성하고 싶을 때 가장 권장하는 위치는 어플리케이션 델리게이트의 applicationDidFinishLaunching 메소드 임
통상 탭바컨트롤러는 어플리케이션 윈도우의 루트뷰를 저공하므로 어플리케이션을 기동한 직후 윈도우를 표시하기전에 탭바컨트롤러를 작성할 필요가 있음
프로그램안에 작성 순서
1. 신규의UITabBarController오브젝트를 작성
2. 탭별로 한 개씩의 커스텀 루트 뷰 컨트롤러를 작성
3. 루트뷰컨트롤러들을 배결에 추가해 탭바컨트롤러의 viewControllers프로퍼티에 할당
4. 탭바컨트롤러의 뷰를 어플리케이션의 메인윈도우에 추가
어플리케이션의 메인윈도우에 탭바 컨트롤러의 인터페이스를 작성해서 인스톨하기위해 필요한 기본적인 코드
- (void)applicationDidFinishLaunching:(UIApplication *)application {
tabBarController = [[UITabBarController alloc] init];
MyViewController* vc1 = [[MyViewController alloc] init];
MyOtherViewController* vc2 = [[MyOtherViewController alloc] init];
NSArray* controllers = [NSArray arrayWithObjects:vc1, vc2, nil];
tabBarController.viewControllers = controllers;
// Tab Bar Controllerの現在のビューをウインドウのサブビューとして追加する
[window addSubview:tabBarController.view];
}
n 프로그램으로 탭바아이템을 작성
탭바인터페이스의 각 루트뷰 컨트롤러에는 각각에 대응하는 탭에 표시하는 화상과 텍스트를 가진 UITabBarItem 오브젝트를 제공해야함
탭바 인터페이스가 표시되기전에는 언제든 탭바 아이템을 뷰 컨트롤러에 연결가능함
해당 오브젝트는 탭바아이템을 각각에 대응하는 뷰컨트롤러의 tabBarItem프로퍼티에 할당
탭바아이템을 작성하는 이상적인 시기는 뷰컨트롤러자신의 초기화중이지만 통상 위의 경우는 커스텀뷰컨트롤러의 경우뿐임 뷰컨트롤러를 작성해서 초기화하고 탭바아이템을 작성해서 연결시키는 것이 가능함
커스텀뷰컨트롤러에 탭바아이템을 작성하는 예
- (id)init {
if (self = [super initWithNibName:@"MyViewController" bundle:nil]) {
self.title = @"My View Controller";
UIImage* anImage = [UIImage imageNamed:@"MyViewControllerImage.png"];
UITabBarItem* theItem = [[UITabBarItem alloc] initWithTitle:@"Home"
image:anImage tag:0];
self.tabBarItem = theItem;
[theItem release];
}
return self;
}
u 실행시 탭의 관리
n 탭바 인터페이스를 작성한후에는 몇가지의 방법을 사용해 인터페이스를 변경하거나 어플리케이션내의 변화에 대응가능
탭의 추가나 삭제가 가능
델리게이트오브젝트를 사용해서 동적인 조건을 기반으로 탭의 선택을 금지시키는것도 가능
각각의 탭에 뱃지를 추가해서 유저에게 해당탭에 주의시키는것도 가능
n 탭의 삭제와 추가
탭바 인터페이스안 탭의 수가 동적으로 변화할 경우 필요에 따라 실행시에 적절한 변경이 가능함
작성시에 탭을 설정하는 방법과 같이 적절한 뷰컨트롤러셋을 탭바컨트롤러에 할당함으로서 실행시에 탭을 변경함
유저에게 시각적인 효과를 주면서 탭을 추가하거나 삭제할경우에는 setViewControllers:animated:를 사용해서 탭변경을 에니메이션화 하는 것 도 가능
현재 선택된 탭내의 특정버튼에 의해 해당탭을 삭제하는 메소드
- (IBAction)processUserInformation:(id)sender {
if ([self userDataIsValid]) {
NSMutableArray* newArray = [NSMutableArray
arrayWithArray:self.tabBarController.viewControllers];
[newArray removeObject:self];
[self.tabBarController setViewControllers:newArray animated:YES];
}
}
n 탭 선택 금지
유저가 탭을 선택하지 못하게 할경우에는 델리게이트오브젝트를 준비해서 tabBarController:shouldSelectViewController:메소드를 작성함
탭의 선택을 금지하는 경우는 예를들면 어플리케이션에서 유저에게 아이디 패스워드의 입력을 요구할경우 입력을 받는 태그이외의 태그를 무효로 하는 것이 가능
위의 상황의 예제 코드 hasValidLogin메소드는 입력된 정보를 검증하기위해 작성한 커스텀 메소드
shouldSelectViewController:(UIViewController *)viewController {
if (![self hasValidLogin] && (viewController != [aTabBar.viewControllersobjectAtIndex:0]) ) {
return NO;
}
return YES;
}
n 유저의 의한 탭의 변경을 감시
탭바에서 유저에의해 발생하는 변경에는 아래의 두가지가 있음
유저가 탭을 선택함
유저가 탭의 배치를 변경함
두경우 모두 탭바컨트롤러의 델리게이트에 보고됨
델리게이트는 UITabBarControllerDelegate프로토콜에 준비한 오브젝트임
델리게이트를 준비해서 유저에의한 변경을 추적하거나 변경에따라서 어플리케이션의
상태정보를 갱신가능
다만 표시나 비표시중의 뷰컨트롤러가 일반적으로 처리하는 작업을 실행하기위해 위의
통지를 사용하는건 안됨
예를들어 현재선택된 뷰의 스타일에 어울리는 스테이터스바의 디자인을 변경하기위해
탭바컨트롤러의 델리게이트를 사용하지 않음
위의 경우에는 커스텀뷰컨트롤러에서 처리하는게 최선임
n 탭의 커스터마이즈 금지
「More」뷰 컨트롤러에는 탭바에 표시하는 항목을 유저가 수정가능하게 하는 기능이 내장되어있음
여러 개의 탭을 가진 어플리케이션의 경우 유저는 위의 기능을 이용해서 바로 엑세스 가능한 화면과
엑세스하기위해 추가의 네비게이터가 필요하게되는 화면을 선택 가능함
아래 화면에서 왼쪽화면 상단의 edit버튼을 탭하면 오른쪽화면으로 자동으로 표시전환됨
이화면에서 새로운 항목을 탭바에 드래그함으로서 탭바의 내용을 교체하는게 가능함
대부분의 경우에는 탭의 배치변경을 유저에게 허가하지만 특정탭을 탭바에서 삭제하거나 특정 탭을
탭바에 배치하는 조작을 유저에게 허가하고싶지 않을경우에는 뷰컨트롤러오브젝트의 배열을
customizableViewControllers프로퍼티에 할당함 이 배열에는 배치를 변경해도 좋은 뷰컨트롤러의
서브셋을 포함함 위의 배열에 포함되지않은 뷰컨트롤러는 배치변경화면에 표시되지 않음
따라서 탭바에 표시되고 있는 뷰컨트롤러를 탭바에서 삭제하는 것은 불가능함
중요 : 탭바인터페이스에서 뷰컨트롤러를 추가하거나 삭제하거나하면 커스터마이즈가능한
뷰컨트롤러의 배열도 디폴트값으로 리셋되어 모든 뷰컨트롤러가 커스터마이즈가능한 상태로 돌아감
따라서 viewControllers프로퍼티를(직접 또는 setViewControllers:animated:메소드를 호출해서)
변경했을 때 계속해서 커스터마이즈 가능한 뷰컨트롤러를 제어할경우에는
customizableViewControllers프로퍼티내의 오브젝트의 배열도 변경할 필요가 있음
n 뱃지의 변경
통상 탭바인터페이스의 탭의 외견은 그탭이 선택될 때 이외에는 변화하지 않음
다만 특정의 탭에 주의를 주고싶은 경우에는 (해당탭에 유저에게 보이고싶은 새로은 컨텐츠가
생긴경우 등) 배지를 추가하는 것이 가능
뱃지는 탭의 구석에 표시되는 빨간 표시임 뱃지의 내부에는 개발자가 제공하는 특정
텍스트가 표시됨
통상 뱃지에는 그탭에서 이용가능한 신규항목의 수를 표시하는 숫자가 표시되나 짧은
문자를 지정하는것도 가능함
탭에 뱃지를 추가할때는 해당 탭바아이템의 badgeValue프로퍼티에 nil이외의 값을 할당함
예를들어 뱃지내에 신규항목의 수를 표시하는 뷰 컨트롤러에는 아래와 같은 코드를 사용해서
뱃지의 값을 작성함
if (self.numberOfNewItems == 0)
self.tabBarItem.badgeValue = nil;
else
self.tabBarItem.badgeValue = [NSString stringWithFormat:@"%d",self.numberOfNewItems];
뱃지의 값을 표시하거나 변경하는 타이밍을 결정하는 것은 개발자의 책임임
다만 뷰컨트롤러에 뱃지용의 값을 가진 프로퍼티가 포함된 경우에는 KVO통지를 사용해서 값의
변화를 검출해서 그것에 따라 뱃지를 갱신가능함
u 탭바 컨트롤러와 뷰의 회전
n 탭바 컨트롤러는 디폴트로 세로방향을 서포트함 모든 루트뷰컨트롤러가 가로방향을 서포트하지않는한 가로방향으로 회전하지 않음 디바이스의 방향이 변화하면 탭바컨트롤러는 뷰컨트롤러의 배열에 문의해 1개라도 가로방향을 서포트하지않는 뷰컨트롤러가 있으면 회전 하지 않음
u 탭바와 풀스크린레이아웃
n 탭바 컨트롤러는 다른 대부분의 뷰컨트롤러와는 다른 방법으로 풀스크린레이아웃을 서포트함
스테이터스바나 네비게이션바의 배경에 뷰를 겹치고 싶을때는 커스텀뷰컨트롤러의 wantsFullScreenLayout프로퍼티를 YES로 설정함
위의 프로퍼티를 YES로 설정해도 탭바뷰의 배경에 뷰를 겹치는 것은 불가능
탭바 컨트롤러는 탭바의 배경에 뷰가 겹치지 않도록 항상 뷰의 사이즈를 변경함
[아이폰개발] 참고 사이트 (0) | 2011.02.16 |
---|---|
[아이폰개발] 메세징 원리 라이브러리 미번역 (0) | 2011.02.10 |
[아이폰개발] hpple 사용예 (0) | 2011.01.28 |
[아이폰개발] 오브젝트별 참고사이트 (0) | 2011.01.21 |
[아이폰개발] Objective-C 8.Enabling Static Behavior (0) | 2011.01.13 |
u Enabling Static Behavior
n Objective-C 동적 특징
- 오브젝트용 메모리는 새인스턴스를 작성하는 클래스메소드에 의해 실행시 할당받음
- 오브젝트는 동적으로 형정의 됨. 컴파일시 자동으로 정의된 id형에서 프로그램이 실핼될때까지
정해지지않음
- 오브젝트 지향 프로그래밍에 높은 유난성을 제공
- 컴파일러가 id형의 변수의 형체크가 불가능
- 클래스명을 정적으로 형정의하거나 형정의 시점을 실행시에서 컴파일시로 되돌릴수있게 필요없는
기능을 오프시킬수 있음
n 오버해드 검출 툴
Shark, Instruments
n 정적 형정의
Rectangle *thisObject; |
- 정적으로 형정의된 오브젝트는 id로 정의된 오브젝트와 동일한 내부구조를 가지게 됨
- 실행시의 오브젝트 처리방법에도 영향없음 id로 동적정의된 오브젝트와 같이 동적 바인딩 됨
Rectangle *thisObject = [[Square alloc] init]; |
- 위의 경우 thisObject는 Rectangle의 인스턴스변부뿐아니라 Square의 인스턴스변수도 가지게 됨
(Square는 Rectangle의 서브클래스)
[thisObject display]; |
- 메세지 역시 실행시 동적 바인드 됨.
- 위의 메세지의 경우 Rectangle슈퍼클래스의 메소드가 아니라 Square 클래스에 정의 된 메소드를 실행함
n 정적 형정의의 특징
- 정적형정의는 조건에 따라 컴파일시 형체크를 할수있음
- 정적 형정의에 의해 같은 이름의 메소드는 같은 반환형과 인수를 가질 필요가 있다는 규칙을 무시할수있음
- 구조체 포인터연산자를 사해서 오브젝트안의 인스턴스변수에 직접 엑세스가 가능함
n 형체크
- 정적으로 형정의된 리시버에 메세지를 보내면 컴파일러는 리시버가 응답가능한지를 체크
응답 불가능한 경우에는 경고발생
- 정적으로 형정의한 오브젝트를 변수에 할당하면 컴파일러가 호환가능한지를 체크
호환불가능한 경우에는 경고 발생
Shape *aShape; Rectangle *aRect; aRect = [[Rectangle alloc] init]; aShape = aRect; |
Rectangle이 Shape를 계승하고 있다는 가정하에 위의 경우 호환성 통과
반대의 경우 호환성 경고
- 대입 연산자의 한쪽이 id형인 경우 호환성 체크 안함
n Return and Argument Types
- 반환형과 인자형의 경우 동적 바인딩때문에 같은 이름의 메소드의 경우 일치시킬 필요가 있음
- 메세지를 정적으로 형정의한 오브젝트에 송신하는 경우 컴파일러가 오브젝트를 인식하기 때문에
반환형과 인자형을 일치시킬 필요가 없음
n Inherited Class에의 형정의
- 인스턴스는 자신의 클래스나 계승받은 클래스를 정적으로 재정의 할수 있음
Shape *myRectangle = [[Rectangle alloc] init]; |
- 위의 경우 컴파일러는 Rectangle을 Shape로 처리함
BOOL solid = [myRectangle isFilled]; |
- isFilled메소드가 Rectangle의 메소드라고 가정 위의 메세지는 에러발생
[myRectangle display]; |
- display메소드가 Shape에서 인식가능한 경우 Rectangle에서의 오버라이드 여부에 관계없이
정상 컴파일
[아이폰개발] hpple 사용예 (0) | 2011.01.28 |
---|---|
[아이폰개발] 오브젝트별 참고사이트 (0) | 2011.01.21 |
[아이폰개발] Objective-C 7.Fast Enumeration (0) | 2011.01.12 |
[아이폰개발] Objective-C JSON 통신 모듈 (0) | 2010.12.29 |
[아이폰개발] Objective-C 6.Associative References (0) | 2010.12.20 |
u Fast Enumeration
n 정의
반복문
Objective-C 2.0에 새로 추가된 기능
NSFastEnumeration 프로토콜을 지원하는 모든 컬렉션(NSArray, NSDictionary, NSSet, NSEnumerator)에서 사용가능.
직접 만든 컬렉션에서 fast enumeration을 지원할려고 하면 NSFastEnumeration 프로토콜을 지원하면 된다.
// one
|
n NSArray 예제
NSArray *array = [NSArray arrayWithObjects:@"One", @"Two", @"Three", @"Four", nil]; |
n NSDictionary 예제
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys: @"quattuor", @"four", @"quinque", @"five", @"sex", @"six", nil]; |
n NSArray ? nextObject 예제
NSArray *array = [NSArray arrayWithObjects:@"One", @"Two", @"Three", @"Four", nil]; |
n index를 이용한 예제
NSArray *array = /* assume this exists */; NSUInteger index = 0; for (id element in array) { NSLog(@"Element at index %u is: %@", index, element); index++; } |
n 아래 두가지 예제는 조건에 따라 일부 처리 요소를 제외할 수 도 있다는 것을 보여줌
NSArray *array = /* assume this exists */; for (id element in array) { if (/* some test for element */) { // statements that apply only to elements passing test } } |
NSArray *array = /* assume this exists */; NSUInteger index = 0; for (id element in array) { if (index != 0) { NSLog(@"Element at index %u is: %@", index, element); } if (++index >= 6) { break; } } |
[아이폰개발] 오브젝트별 참고사이트 (0) | 2011.01.21 |
---|---|
[아이폰개발] Objective-C 8.Enabling Static Behavior (0) | 2011.01.13 |
[아이폰개발] Objective-C JSON 통신 모듈 (0) | 2010.12.29 |
[아이폰개발] Objective-C 6.Associative References (0) | 2010.12.20 |
[아이폰개발] Objective-C 5.카테고리와 확장 (0) | 2010.12.20 |
[아이폰개발] Objective-C 8.Enabling Static Behavior (0) | 2011.01.13 |
---|---|
[아이폰개발] Objective-C 7.Fast Enumeration (0) | 2011.01.12 |
[아이폰개발] Objective-C 6.Associative References (0) | 2010.12.20 |
[아이폰개발] Objective-C 5.카테고리와 확장 (0) | 2010.12.20 |
[아이폰개발] Objective-C 4.프로퍼티 (0) | 2010.12.17 |
u Associative References
n 용도
기존의 클래스오브젝트의 인스턴스변수를 의사적으로 추가
Associative References는 Mac OS X v10.6이후 에서만 사용 가능
n Adding Storage Outside a Class Definition
클래스 선언을 변경하지않고 오브젝트에 스토리지를 추가 가능
클래스 소스코드에 접근 불가한 경우에 사용 가능
n Creating Associations
런타임 함수 objc_setAssociatedObject를 사용
objc_setAssociatedObject는 4개의 인수가 필요 (소스오브젝트, 값, 키, 폴리시정수)
키(void포인터) : static변수를 사용하는 것이 일반적
폴리시정수 : 관련오브젝트를 대입할것인지, 유지할것인지, 복사할것인지를 지정
static char overviewKey; NSArray *array = [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil]; NSString *overview = [[NSString alloc] initWithFormat:@"%@", @"First three numbers"]; objc_setAssociatedObject(array, &overviewKey, overview, OBJC_ASSOCIATION_RETAIN); [overview release]; // (1) overview valid [array release]; // (2) overview invalid |
n 관련 오브젝트의 취득
NSString *associatedObject = (NSString *) objc_getAssociatedObject(array,&overviewKey); |
n Breaking Associations
objc_setAssociatedObject(array, &overviewKey, nil, OBJC_ASSOCIATION_ASSIGN); |
[아이폰개발] Objective-C 7.Fast Enumeration (0) | 2011.01.12 |
---|---|
[아이폰개발] Objective-C JSON 통신 모듈 (0) | 2010.12.29 |
[아이폰개발] Objective-C 5.카테고리와 확장 (0) | 2010.12.20 |
[아이폰개발] Objective-C 4.프로퍼티 (0) | 2010.12.17 |
[아이폰개발] Objective-C 3.프로토콜 (0) | 2010.12.16 |
u 카테고리와 확장
n 의미
기본은 수직상속만 가능, 메소드를 추가해야할 경우 수직상속
카테고리를 사용함으로서 메소드의 수평적 상속이 가능
소스를 가지고 있는 않은 클래스에도 추가할 수 있음
카테고리를 사용해서 클래스의 implementation을 여러 파일로 쪼갤 수 있음
선언과 구현이 분리되어 있고, 클래스에 종속되어 있지 않음
n Adding Methods to Classes
카테고리가 클래스에 추가한 method들은 그 클래스의 subclass에 의해 상속
#import "ClassName.h" @interface ClassName ( CategoryName ) // method declarations
@end |
-특징
파일명이 ClassName+CategoryName.m으로 됨
#import "ClassName+CategoryName.h" @implementation ClassName ( CategoryName ) // method definitions
@end |
오직 method만 추가할 수 있음
클래스 scope의 모든 instance variables(@private조차도)는 카테고리의 scope이므로
모두 접근이 가능
무한정 작성 가능
n How you Use Categories
다른 implementation에 의해 정의된 클래스들을 확장할 때
Cocoa frameworks에 정의된 클래스들에 method들을 추가할 때
subclass의 대안으로 쓰려고 할 때
새 클래스의 implementation을 몇 개의 소스 화일로 분배하려 할 때
informal protocol을 선언하기 위해
n Categories of the Root Class
super에 대한 message는 불가능
class object는 루트 클래스에 정의된 instance method를 수행할 수 있다
보통 class object는 class method만 수행하지만 루트 클래스에 정의된 instance method는
특별한 경우이다.
카테고리로 추가한 instance method가 루트 클래스에서 수행되므로 예측이 불가능하게 되어 루트
클래스에 카테고리 사용은 바람직하지 못하다.
[아이폰개발] Objective-C JSON 통신 모듈 (0) | 2010.12.29 |
---|---|
[아이폰개발] Objective-C 6.Associative References (0) | 2010.12.20 |
[아이폰개발] Objective-C 4.프로퍼티 (0) | 2010.12.17 |
[아이폰개발] Objective-C 3.프로토콜 (0) | 2010.12.16 |
[아이폰개발] Objective-C 2.오브젝트의 메모리 할당과 초기화 (0) | 2010.12.15 |
u 프로퍼티
n 프로퍼티 선언
Property를 사용하기 위해서 일반적으로 @property 지시자와 @synthesize 지시자를 함께 사용
@property 지시자는 클래스의 @interface 내부에 선언하며 다음과 같은 형식으로 선언
@interface MyClass : NSObject { float value; } @property float value;
@end |
@property float value |
위의 선언은 다음과 같이 두가지 메서드를 선언한것과 같은 기능
- (float)value;
- (void)setValue:(float)newValue; |
n @synthesize
구현부안에 getter, setter를 지정안했을경우@synthesize를 통해 컴파일러에게 작성을 지시함
- 주의
@synthesize를 사용안할 경우 직접 구현부에 getter, setter를 작성해야 컴파일 가능하나
문제가 발생할 여지가 있으므로@synthesize사용을 권장
n @property 지시자의 attributes
- getter=gettername
기본적으로 Property의 getter 메서드 명은 Property 자신의 이름과 동일 (예 : Property가 foo일 경우 foo) 하지만 이 기본 설정을 내가 원하는 메서드명으로 변경 할 수 있습니다.
- setter=settername
Property의 setter 메서드 명은 setPropertyName: 입니다. (예 : Property가 foo일 경우 setFoo:)
역시나 이 기본 설정을 내가 원하는 메서드명으로 변경 할 수 있습니다.
- readwrite (DEFAULT)
Property의 값을 읽고 쓸 수 있다는 것입니다. 이 설정은 기본 설정입니다.
- readonly
Property의 값을 단지 읽기만 할수 있다고 정의하는 속성입니다.
이 속성은 @implementation 블럭 안에서 오로지 getter 메서드만 필요할 경우에 사용합니다.
@synthesize 지시자를 사용하였을 경우에는 역시나 getter 메서드의 역할만을 하게 됩니다.
값을 대입 하려고 할 경우 에러를 출력하게 됩니다.
- assign (DEFAULT)
단순하게 값을 대입합니다. 기본설정입니다.
이전에 어떤 객체를 가리키고 있던 Property라면 이로 인해 해당 객체는 미아가 되어 메모리릭의 주범이 될 수 있습니다.
가비지콜렉터를 사용하지 않는다면 사용을 피해야 합니다.
- retain
이 것은 assign과 비슷하지만 조금 다릅니다.
이전에 가리키고 있던 객체가 있다면 해당 객체를 Release하여 메모리에서 제거 합니다.
- copy
객체를 바로 대입하지 않고 해당 객체의 복사 메서드를 Invoke호출합니다.
그리하여 다른 메모리 영역에 복사본을 만든 다음 그것을 반환하게 됩니다.
이전에 가리키고 있던 값은 Release 시킵니다.
- nonatomic
이 속성은 접근자 메서드가 Atomic 하지 않게 동작하게 합니다.
기본적으로 접근자는 Atomic하게 동작합니다.
Atomic 이라는 말은 멀티스레드 등으로 구성된 프로그램이 특정 접근자 메서드를 호출할때 서로 충돌이 나지 않도록 객체 레벨에서 Lock을 걸고 Property에 접근하게 됩니다.
이런 접근이 필요없다면 이 속성을 사용하여 Non-Atomic하게 동작하도록 만들어 주시는 것이 좋습니다.
- dealloc
객체가 제거 될때 소멸자로 dealloc이 호출되는데 Property들이 자동으로 소거되지 않아
명시적으로 제거해 주셔야 합니다.
- (void)dealloc { [property release]; [super dealloc];
} |
n 재선언
서브클래스에서 슈퍼클래스의 프로퍼티의 재선언 가능
속성 선언을 다시 해줘야함
n Markup and Deprecation
@property CGFloat x AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_4; @property CGFloat y __attribute__((...)); |
[아이폰개발] Objective-C 6.Associative References (0) | 2010.12.20 |
---|---|
[아이폰개발] Objective-C 5.카테고리와 확장 (0) | 2010.12.20 |
[아이폰개발] Objective-C 3.프로토콜 (0) | 2010.12.16 |
[아이폰개발] Objective-C 2.오브젝트의 메모리 할당과 초기화 (0) | 2010.12.15 |
[아이폰개발] Objective-C 1.클래스 정의 (0) | 2010.12.15 |
u 프로토콜
n 정의
Protocols는 클래스 정의와 관련 없는 mothod선언 목록.
Protocols는 정의되어 있지 않은 객체에 메시지를 전달하고자 할 때 사용 가능
n 사용 범위
- 다른 사람들이 구현해야 할 mothod를 선언할 때
- 클래스는 숨긴 상태에서 object의 interface을 선어할 때
- 계층적으로 관련없는 클래스 간에 유사성을 가지게 할 때
n Declaring Interfaces for Others to Implement
프로토콜로 선언된 메소드를 사용하려면, 프로토콜을 adopt(클래스가 프로토콜의 모든 메소드를 구현한다는 의미)하고, 그 메소드들을 구현.
- (void)mouseDown:(NSEvent *)theEvent; - (void)mouseDragged:(NSEvent *)theEvent; - (void)mouseUp:(NSEvent *)theEvent; |
n Methods for Others to Implement
- setAssistant:anObject { assistant = anObject; } |
n Declaring Interfaces for Anonymous Objects
id formatter = [receiver formattingService]; |
n Non-Hierarchical Similarities
- (NSXMLElement *)XMLRepresentation; - initFromXMLRepresentation:(NSXMLElement *)xmlString; |
n Formal Protocols (선언 방법)
@protocol 지시자를 사용
@protocol ProtocolName method declarations @end |
n XML을 이용한 protocol 표현이 가능
@protocol MyXMLSupport - initFromXMLRepresentation:(NSXMLElement *)XMLElement; - (NSXMLElement *)XMLRepresentation; @end |
n 주의점
- protocol은 클래스랑 연관지어 쓰는 것으로 단독으로 사용되지 않는다.
따라서, protocol 이름은 자체의 namespace안에만 있게 되어 global하게 접근할 수 없다.
- protocol을 사용하려면 class가 그 protocol을 adopt해야 한다.
- protocol을 adopt할 클래스에서는 protocol이 선언된 헤더파일을 import 해야 한다.
n Informal Protocols(Category 선언 내에 method를 선언한 것)
@interface NSObject ( MyXMLSupport ) - initFromXMLRepresentation:(NSXMLElement *)XMLElement; - (NSXMLElement *)XMLRepresentation; @end |
특징
- informal protocol은 category와 선언방식은 똑같다.
차이점은 Catogory는 구현을 따로 카테고리로 만들어서 해야 하는 반면,
informal protocol은 구현을 클래스의method로 해 준다
n Protocol Objects
런타임시 클래스는 class object로 method는 selector로 formal protocol은 protocol class로
protocol object는 @protocol(protocol_name)지시자로 참조할 수 있다.
Protocol *myXMLSupportProtocol = @protocol(MyXMLSupport); |
n Adoption a Protocol(adopt는 클래스가 protocol의 모든 mothod를 구현한다는 의미)
@interface ClassName : ItsSuperclass < protocol list > @interface ClassName ( CategoryName ) < protocol list > @interface Formatter : NSObject < Formatting, Prettifying > |
n Conforming to a Protocol
-클래스가 protocol을 adopt하고 있는지 알아보기 위해 conformsToProtocol:메시지를 object에 보낸다.
-respondsToSelector:는 한 method이 구현되어 있는지를 알려준다.
-isKindOfClass:는 클래스가 상속 계층구조안에 속하는지 여부를 알려준다.
if ( ! [receiver conformsToProtocol:@protocol(MyXMLSupport)] ) { // Object does not conform to MyXMLSupport protocol // If you are expecting receiver to implement methods declared in the // MyXMLSupport protocol, this is probably an error } |
n Type Checking
protocol 타입선언 방법은 “type_name <protocol_name> 변수” 형태이다.
- (id <Formatting>)formattingService; id <MyXMLSupport> anObject; Formatter *anObject; id <Formatting> anObject; |
n Protocols Within Protocols
@protocol ProtocolName < protocol list > @protocol Paging < Formatting > id <Paging> someObject; if ( [anotherObject conformsToProtocol:@protocol(Paging)] ) |
n 상호참조 문제 해결
// A 선언 #import "B.h" @protocol A - foo:(id <B>)anObject; @end // B 선언 #import "A.h" @protocol B - bar:(id <A>)anObject; @end // A, B protocol이 상호 참조 @protocol B; @protocol A - foo:(id <B>)anObject; @end |
[아이폰개발] Objective-C 5.카테고리와 확장 (0) | 2010.12.20 |
---|---|
[아이폰개발] Objective-C 4.프로퍼티 (0) | 2010.12.17 |
[아이폰개발] Objective-C 2.오브젝트의 메모리 할당과 초기화 (0) | 2010.12.15 |
[아이폰개발] Objective-C 1.클래스 정의 (0) | 2010.12.15 |
[아이폰개발] 오브젝트C 한글 레퍼런스 (2) | 2010.12.08 |