カスタムクラスを書く
iOS アプリを開発する時に独自のカスタムクラスを作成する必要がある多くの機会があります。データと一緒にカスタムの動作をパッケージ化する必要がある場合に、カスタムクラスは便利です。カスタムクラスでは、保存、操作、およびデータを表示するための独自の動作を定義することができます。
たとえば、iOS の時計アプリ内の[世界時計]タブを考えてください。このテーブルビュー内のセルは、標準のテーブルビュー・セルより多くのコンテンツを表示する必要があります。これは、指定されたテーブルビュー・セルに、追加のカスタムデータを表示できるように UITableViewCell の動作を拡張するサブクラスを実装するための良い機会です。このカスタムクラスを設計している場合は、セルの右側にある独自 (カスタム) の時計を表示するための情報とイメージ・ビューを表示するには、ラベルのアウトレットを追加することができます。
この章では、ToDoList アプリの動作の実装を完了するために Objective-C の文法とクラスの構造についての知識を教えます。この章は、ToDoItem、To-Do リスト上の一つの項目を表すカスタムクラスのデザインについて説明します。第三のチュートリアルでは、実際にこのクラスを実装し、あなたのアプリに追加します。
クラスの宣言と実装
Objective-C のクラスの仕様で、2つの部分を必要とします、すなわちインタフェースと実装です。インターフェース は、オブジェクトの指定された型が、他のオブジェクトによって使用されることをいかに意図されているかを正確に指定します。言い換えれば、それはクラスのインスタンスと外界との間の公的なインターフェイスを定義しています。実装 は、インターフェースで宣言された各メソッドの実行可能なコードを含んでいます。
オブジェクトは、その内部の実装の詳細を隠すようにデザインする必要があります。Objective-C では、インタフェースと実装は、通常は別々のファイルに置かれ、インタフェースを public にするだけの必要があります。C コードと同じように、コードの実装の詳細から public の宣言を分離するためヘッダファイルとソースファイルを別々に定義します。インタフェースファイルは、.h 拡張子を持ち、実装ファイルは、.m 拡張子を持っています。(実際には チュートリアル:データ追加 内で ToDoItem クラスのこれらのファイルを作成します。今は、作品のすべての部分が紹介されるのに従って下さい。)
インターフェース
クラス・インターフェイスを宣言するため使用する Objective-C の構文は次のようになります。
- @interface ToDoItem : NSObject
- @end
この例では、Object から継承した ToDoItem という名前のクラスを宣言しています。
public (公的) なプロパティと動作は、@interface 宣言の内部で定義されています。この例では、何もスーパークラスを超えて指定されていないので、 ToDoItem のインスタンスで利用可能になる予定の動作のみが NSObject から継承されている動作です。すべてのオブジェクトは、最小限の動作を有するように期待されているので、デフォルトでは、それらは NSObject (またはそのサブクラスの一つ) から継承する必要があります。
実装
クラスの実装 (Implementation) を宣言するために使用される Objective-C の構文は次のようになります。
- #import "ToDoItem.h"
- @implementation ToDoItem
- @end
クラス・インターフェイスの任意のメソッドを宣言する場合は、このファイルの中にそれらを実装する必要があります。
プロパティがオブジェクトのデータを格納
to-do 項目が保持する必要のある情報が何かを検討してください。それが作成されたときに、その名前と、それが完了したのかどうか、知っている必要がおそらくあるでしょう。 ToDoItem カスタムクラスでは、プロパティ にこの情報を格納します。
これらのプロパティの宣言はインターフェイス・ファイル (ToDoItem.h) の内側にあります。それらはこのようなものです:
- @interface ToDoItem : NSObject
- @property NSString *itemName;
- @property BOOL completed;
- @property NSDate *creationDate;
- @end
この例では、ToDoItem クラスでは、3つの public プロパティを宣言しています。他に指定しなくても、他のオブジェクトはこのプロパティの値を読んだり変更したりできます。
プロパティが読み取り専用であることを宣言するには、それを property attribute (プロパティ属性) に指定します。例えば、ToDoItem の作成日を変更したくない場合には、ToDoItem クラス・インターフェイスを以下の様に更新できます。
- @interface ToDoItem : NSObject
- @property NSString *itemName;
- @property BOOL completed;
- @property (readonly) NSDate *creationDate;
- @end
プロパティは、private または public にすることができます。時には他のクラスが参照できない、あるいはアクセスできないように、プロパティを非公開 (private)にする意味があります。例えば、項目が完成された日付を表すプロパティを追跡したい時に、この情報を他のクラスにアクセスさせないようにするには、実装ファイル (ToDoItem.m) の先頭で #import 文を加えた後 class extension(クラス拡張) をしてこのプロパティを以下の様に private にします。
- #import "ToDoItem.h"
- @interface ToDoItem ()
- @property NSDate *completionDate;
- @end
- @implementation ToDoItem
- @end
プロパティにアクセスするには、ゲッタとセッタを使用します。ゲッタ は、プロパティの値を返し、セッタ はそれを変更します。ゲッタとセッタにアクセスするための一般的な短縮構文は、ドット表記法 です。読み取りと書き込みのアクセス権を持つプロパティについては、プロパティの値を取得および設定の両方にドット表記を使用できます。ToDoItem クラスの toDoItem オブジェクトがある場合は、次の様に記載できます。
- toDoItem.itemName = @"Buy milk";                              //Sets the value of itemName
- NSString *selectedItemName = toDoItem.itemName;    //Gets the value of itemName
メソッドがオブジェクトの動作を定義
メソッドは、オブジェクトに何ができるかを定義します。メソッド は、クラス内のタスクまたはサブルーチンの実行を定義する、ほんのコードの切れ端です。メソッドは、クラスに格納されたデータにアクセスでき、操作を実行するためにその情報を使用することができます。
例えば、To-Do 項目 (ToDoItem) に、完了したものとしてマークされてる機能を提供するには、クラスインターフェイスに markAsCompleted メソッドを追加することができます。後で、メソッドを実装する に記載したように、クラスの実装は、このメソッドの動作を実装します。
- @interface ToDoItem : NSObject
- @property NSString *itemName;
- @property BOOL completed;
- @property (readonly) NSDate *creationDate;
- - (void)markAsCompleted;
- @end
メソッド名の先頭のマイナス記号 (-) は、そのクラスのオブジェクトで呼び出すことができる インスタンスメソッド であることを示します。このマイナス記号はクラスメソッドでは異なり、プラス記号 (+) で示されます。クラスメソッド は、クラス自身で呼び出すことができます。クラスメソッドの一般的な例は、Foundation での作業 で学んだクラスファクトリ·メソッドです。また、クラスに関連付けられた共有情報のいくつかの部分にアクセスするためのクラスメソッドも使用できます。
void キーワードは、宣言の冒頭で、括弧の内部で使用され、メソッドが値を返さないことを示します。この場合、 markAsCompleted メソッドはパラメータを取りません。パラメータは、メソッドのパラメータ で詳しく説明します。
メソッドのパラメータ
メソッドを呼び出したときに、情報のいくつかの部分に沿って渡す パラメータ を持つメソッドを宣言します。
たとえば、完了したか完了しないかを決定する一つのパラメータを取る、以前のコードスニペットから markAsCompleted メソッドを修正できます。このようにして、完成したとだけ設定する代わりに、完了状態を切り替えることができます。
- @interface ToDoItem : NSObject
- @property NSString *itemName;
- @property BOOL completed;
- @property (readonly) NSDate *creationDate;
- - (void)markAsCompleted:(BOOL)isComplete;
- @end
さあ、メソッドは BOOL 型である一つのパラメータ、isComplete、を取ります。
名前でパラメータを指定してメソッドを参照するときには、メソッド名の一部としてコロン(:)を含めなければないため、更新したメソッドの名前は、 markAsCompleted: になります。メソッドに複数のパラメータがある場合、メソッドの名は分割され、パラメータ名がばらまかれます。このメソッドに別のパラメータを追加したい場合は、その宣言は次のようになります。
- (void)markAsCompleted:(BOOL)isComplete onDate:(NSDate *)date;
ここでは、メソッドの名前は markAsCompleted:OnDate: のように書かれています。名前には、isComplete と date が実装で使われ、これらの名前が変数であるかのように、メソッドが呼び出されたときに、提供された値にアクセスするのに使われます。
メソッドの実装
メソッドの実装は、関連するコードを含む中括弧を使用します。メソッドの名前はインタフェースファイルの相手と同一である必要があり、パラメータや戻り値の型は正確に一致する必要があります。
以前議論した markAsCompleted: メソッドの簡単な実装を示します:
- @implementation ToDoItem
- - (void)markAsCompleted:(BOOL)isComplete {
-         self.completed = isComplete;
- }
- @end
プロパティと同様に、メソッドは、private または public にすることができます。Public メソッドは、public インタフェースで宣言されているので、他のオブジェクトから見え、呼び出す事ができます。それらに対応する実装は、実装ファイル内に存在し、他のオブジェクトに見えません。Private メソッドは、実装だけを持ち、クラス内にあり、クラスの実装内からだけ呼び出す事が出来ます。これは、他のオブジェクトがそれにアクセスすることなく、クラスに内部動作を追加するための強力なメカニズムです。
たとえば、to-do 項目の completionDate の更新を維持したいとしましょう。完成したというマークを to-do 項目に付けたら、 completionDate に現在の日付を設定します。もし未完了とマークされた場合、それが完了していないので、 completionDate に nil を設定します。to-do 項目の completionDate を更新するのは自己完結型のタスクのため、一番いいのは、そのための独自のメソッドを記述することです。しかし、他のオブジェクトがこのメソッドを呼び出すことができないことを確認することが重要ですーそうでなければ、他のオブジェクトが、いつでも何にでも to-do 項目の completionDate を設定することができるでしょう。このような理由から、このメソッドを private にします。
これを実現するために、完了または未完了としてそれがいつマークされようとも、to-do 項目の completionDate を更新するために、markAsCompleted: 内部で呼び出される private メソッド setCompletionDate を含めるように ToDoItem の実装を更新して下さい。他のオブジェクトにこのメソッドを表示したくないので、インターフェイスファイルには何も追加していないことに注意してください。
- @implementation ToDoItem
- - (void)markAsCompleted:(BOOL)isComplete {
-         self.completed = isComplete;
-         [self setCompletionDate];
- }
- - (void)setCompletionDate {
-         if (self.completed) {
-                 self.completionDate = [NSDate date];
-         } else {
-                 self.completionDate = nil;
-         }
- }
- @end
この時点で、ToDoItem クラスを使用して To Do リストの項目の基本的な表現をデザインしました。 ToDoItem は自分自身の情報を格納し、名前、作成日、完了状態、プロパティの形式について、そしてそれが何ができるか定義し、完了したか完了しないかをメソッドを使ってマークします。さあ、次のチュートリアルに移動し、あなたのアプリにこのクラスを追加してみましょう。
前の章:ファウンデーションでの作業
次の章:チュートリアル:データ追加