Foundation での作業
アプリのため Objective-C のコードを書き始めると、利用できる多くのフレームワークを見つけるでしょう。特に重要なのは、すべてのアプリのための基本的なサービスを提供する Foundation フレームワーク です。 Foundation フレームワークは、文字列や数値などの基本的なデータ型を表す 値クラス(Value class) だけでなく、他のオブジェクトを格納するための コレクションクラス(collection class) も含みます。あなたの ToDoList アプリのコードの多くを書くと、値クラスと、コレクションクラスを頼りにするでしょう。
値オブジェクト
Foundation フレームワークは、文字列、バイナリデータ (二進値)、日付と時刻、数値、その他の値のオブジェクトを生成するクラスを提供します。
値オブジェクト は (Cデータ型の) プリミティブ値をカプセル化し、その値に関連するサービスを提供するオブジェクトです。アプリからの呼び出すメソッドや関数のパラメータや戻り値として値オブジェクトに頻繁に遭遇するでしょう。フレームワークの他の部分や全く別のフレームワークは、値オブジェクトを渡すことで、データを交換します。
Foundation フレームワーク内の値オブジェクトの例をいくつか示します。
NSString と NSMutableString
NSData と NSMutableData
NSDate
NSNumber
NSValue
値オブジェクトは、スカラー値を表すので、コレクションとしてそれらを使用でき、また他のオブジェクトが要求されるどこでも使用できます。値オブジェクトは、カプセル化するプリミティブ型以上の利点があります:それらは簡単かつ効率的にカプセル化された値に特定の操作を実行できるようにします。 NSString のクラスには、例えば、ファイルまたは (好みであれば) URL に文字列を書き込んだり、ファイル·システム·パスを構築したり、検索したり、部分文字列を置換するためのメソッドがあります。
プリミティブ型のデータから、値オブジェクトを作成します。NSNumber クラスは、このアプローチの例を提供します。
- int n = 5; // Value assigned to primitive type
- NSNumber *numberObject = [NSNumber numberWithInt:n]; // Value object created from primitive type
後で、オブジェクトからカプセル化されたデータにアクセスできます。
int y = [numberObject intValue]; // Encapsulated value obtained from value object (y == n)
値クラスの多くはイニシャライザーとクラスファクトリ・メソッドの両方を宣言することでそのインスタンスを作成します。クラスファクトリ・メソッド は、クライアントのためコンビニエンスとしてクラスに実装されますが、一度に配置と初期化をされて0作成されたオブジェクトを返します。たとえば、NSString のクラスはクラスの新しいインスタンスを割り当てと初期化をし、あなたのコードに返す string クラスのメソッドを宣言します。
文字列
Objective-C と C は、文字列を指定するための同じ規則をサポートしています:一つの文字は一重引用符で囲み、文字列は二重引用符で囲みます。しかし、Objective-C のフレームワークは、通常、C の文字列を使用しません。その代わりに、NSString オブジェクトを使用します。
NSString クラスは、文字列のオブジェクト・ラッパーを提供し、内蔵メモリの管理をしたり、任意の長さの文字列を格納したり、別の文字エンコーディング (特にユニコード) のサポートをしたり、文字列の書式設定のためのユーティリティを提供します。一般的にこのような文字列を使用していますので、Objective-C は、定数から NSString オブジェクトを作成するための簡略表記を提供しています。この NSString のリテラルを使用するには、次の例に示すように、アットマーク(@)を二重引用符で囲まれた文字列の前に置きます:
- // Create the string "My String" plus newline.
- NSString *myString = @"My String\n";
- // Create the formatted string "1 String".
- NSString *anotherString = [NSString stringWithFormat:@"%d %@", 1, @"String"];
- // Create an Objective-C string from a C string.
- NSString *fromCString = [NSString stringWithCString:"A C string" encoding:NSUTF8StringEncoding];
数字
Objective-C は NSNumber オブジェクトを作成するために、初期化やクラスファクトリメソッドを呼び出す必要がない、簡略表記を提供しています。単純に数値の前にアットマーク (@) を書き、オプションで、値型インジケータを付けてください。たとえば、整数値や double 値をカプセル化して NSNumber オブジェクトを作ることができます:
- NSNumber *myIntValue         = @32;
- NSNumber *myDoubleValue = @3.22346432;
また、カプセル化された、ブール値や文字の値を作成する NSNumber リテラルも使用できます。
- NSNumber *myBoolValue = @YES;
- NSNumber *myCharValue = @'V';
符号なし整数、長整数、長い長整数、浮動小数点値を表す NSNumber オブジェクトを作成するには、表記の値に、それぞれ、U、L、LL、および F を追加することで表記できます。たとえば、float 値をカプセル化した NSNumber オブジェクトを作成するには、次のように書くことができます:
NSNumber *myFloatValue = @3.2F;
コレクションオブジェクト
Objective-C コードのほとんどの コレクション・オブジェクト は、基本的なコレクション・クラスの NSArray、NSSet と NSDictionary のインスタンスです。コレクション・クラスは、オブジェクトのグループを管理するために使用され、コレクションに追加したい項目は、Objective-C クラスのインスタンスでなければなりません。スカラー値を追加する必要がある場合は、まずそれを表現する NSNumber または NSValue インスタンスを作成する必要があります。
コレクションに追加したオブジェクトは、少なくともコレクションが生きている限り生かされます。コレクション・クラスは、そのコンテンツを追跡するために、強力な参照を使用しているからです。その内容を追跡することに加えて、コレクション・クラスの各々は、簡単に特定の項目にアクセスしたり、特定のオブジェクトがコレクションの一部であるかどうかを調べたり、列挙など、特定のタスクを行うことができます。
NSArray、NSSet、及び NSDictionary のクラスの内容は、作成時に設定されます。それらの内容は時間が経っても変更することはできませんので、それらのクラスはは不変(Immutable)と呼ばれます。各々はまた、自由にオブジェクトを追加または削除することが可能な、変更可能(mutable)なサブクラスを持っています。コレクションの型が異なれば、独特の方法で、それに含まれるオブジェクトを整理します。
- NSArray と NSMutableArray。 配列は、オブジェクトの順序の付いたコレクションです。配列内での位置 (つまり、その索引) を指定してオブジェクトにアクセスします。配列の最初の要素は索引 0(ゼロ)です。
- NSSet と NSMutableSet。 セットは、各オブジェクトは一度だけ発生するオブジェクトの順序のないコレクションです。一般的には、セット内のオブジェクトへのテストまたはフィルタを適用することによって、セット内のオブジェクトにアクセスします。
- NSDictionary と NSMutableDictionary。 辞書はキー値のペアとしてエントリを格納します。キーは、唯一の識別子で、通常は文字列であり、値が保存したいオブジェクトです。キーを指定することで、このオブジェクトにアクセスします。
配列
array (NSArray) は、オブジェクトの順序付けられたコレクションを表します。唯一の要件は、各項目が Objective-C のオブジェクトである事で、各オブジェクトには、同じクラスのインスタンスである必要はありません。
配列内の順序を維持するために、各要素はゼロベースの索引に格納されています。
配列の作成
初期化やクラスファクトリ・メソッドを使って配列を作成します。異なる初期化や、ファクトリ・メソッドの様々な方法が、オブジェクトの数に応じて利用可能です。
- + (id)arrayWithObject:(id)anObject;
- + (id)arrayWithObjects:(id)firstObject, ...;
- - (id)initWithObjects:(id)firstObject, ...;
arrayWithObjects: と initWithObjects: メソッドは、引数に、 nil- で終わる、可変の引数を取るので、最後の値として nil を含める必要があります。
- id firstObject = @"someString";
- id secondObject = @"secondString";
- id thirdObject = @"anotherString";
- NSArray *someArray =
- [NSArray arrayWithObjects:firstObject, secondObject, thirdObject, nil];
この例では、3つのオブジェクトを持つ配列を作成します。最初のオブジェクト、 firstObject は、配列インデックスが 0 を持つことになります。最後のオブジェクト、thirdObject は、インデックス 2 を持つことになります。
コンパクトな構文を使用して、配列リテラルを作成することが可能です。
NSArray *someArray = @[firstObject, secondObject, thirdObject];
この構文を使用する場合、nil をリストの最後として使用してはいけませんー事実、 nil は無効な値です。例えば、次のコードを実行しようとした場合、実行時に例外が発生します。
- id nilObject = nil;
- NSArray *someArray = @[firstObject, nilObject];
- // exception: "attempt to insert nil object"
配列オブジェクトに照会
配列を作成した後、このような情報、どれだけ多くのオブジェクトをそれが持っているか、あるいは、それは与えられた項目を含んでいるかどうかについて照会できます。
- NSUInteger numberOfItems = [someArray count];
- if ([someArray containsObject:secondObject]) {
-         ...
- }
また、与えられたインデックスの項目の配列を照会することができます。無効なインデックスを要求しようとすると、実行時に範囲外の例外が起こります。例外が起こるのを避けるために、常に最初に項目の数を確認してください。
- if ([someArray count] > 0) {
-         NSLog(@"First item is: %@", [someArray objectAtIndex:0]);
- }
この例では、項目の数がゼロよりも大きいかどうかをチェックしています。もしそうであれば、Foundation 関数の NSLog は 0 のインデックスを持っている最初の項目の説明を記録します。
objectAtIndex: を使用する代わりに、単に標準 C 言語の配列の値にアクセスするように、サブスクリプト構文を使用して配列を照会します。前の例は次のように書き換えることができます。
- if ([someArray count] > 0) {
-         NSLog(@"First item is: %@", someArray[0]);
- }
配列オブジェクトの並べ替え
NSArray クラスは、収集されたオブジェクトを分類する様々なメソッドを提供しています。NSArray は不変であるため、各メソッドは、ソート順に項目を含む新しい配列を返します。
たとえば、compare: を呼び出すことで文字列の配列を並べ替えることができます。
- NSArray *unsortedStrings = @[@"gamma", @"alpha", @"beta"];
- NSArray *sortedStrings =
-         [unsortedStrings sortedArrayUsingSelector:@selector(compare:)];
配列の可変性
NSArray のクラス自体は不変ですが、それにもかかわらず、変更可能なオブジェクトを含めることができます。たとえば、このような変更可能な文字列を含む不変の配列を作成した場合は:
- NSMutableString *mutableString = [NSMutableString stringWithString:@"Hello"];
- NSArray *immutableArray = @[mutableString];
文字列を変更から止めるものは何もありません。
- if ([immutableArray count] > 0) {
-         id string = immutableArray[0];
-         if ([string isKindOfClass:[NSMutableString class]]) {
-                 [string appendString:@" World!"];
-         }
- }
初期化して配列を作成してオブジェクトを追加あるいは削除したいなら、 NSMutableArray を使用しましょう。それは1つ以上のオブジェクトを、追加、削除、置き換えるための様々なメソッドを追加します。
- NSMutableArray *mutableArray = [NSMutableArray array];
- [mutableArray addObject:@"gamma"];
- [mutableArray addObject:@"alpha"];
- [mutableArray addObject:@"beta"];
- [mutableArray replaceObjectAtIndex:0 withObject:@"epsilon"];
この例では、@"epsilon", @"alpha", そして @"beta" オブジェクトで構成された配列を作成します。
二次的な配列を作成せずに、その場に変更可能な配列を並べ替えることもできます。
[mutableArray sortUsingSelector:@selector(caseInsensitiveCompare:)];
この場合、含まれる項目は昇順、大文字と小文字を区別しないに並べ替えされた、@"alpha", @"beta", そして @"epsilon" の順序になります。
セット
セット (NSSet) オブジェクトは配列に似ていますが、個別のオブジェクトで、順序付けられないグループを維持しています。
セットが順序を維持しないため、それらは会員のためのテストになると配列よりも、高速なパフォーマンスを提供します。
基本の NSSet クラスは不変であるため、初期化やクラスファクトリ・メソッドのいずれかを使用して、作成時にその内容を指定する必要があります。
- NSSet *simpleSet =
-     [NSSet setWithObjects:@"Hello, World!", @42, aValue, anObject, nil];
NSArray のように、initWithObjects: と setWithObjects: メソッドは、両方とも可変個の引数を取り、 nil で終わります。変更可能な NSSet のサブクラスの名前は NSMutableSet です。
何度もオブジェクトを追加してみたい場合でもセットは、個々のオブジェクトへの唯一つの参照を格納します。
- NSNumber *number = @42;
- NSSet *numberSet =
- [NSSet setWithObjects:number, number, number, number, nil];
- // numberSet only contains one object
Dictionary (辞書)
単にオブジェクトの順序付きまたは順序なしコレクションを維持するだけではなく、辞書 (NSDictionary) は、その後の検索のために使用できる与えられたキーに関連付けられている、オブジェクトを保存しています。
最も良い習慣は、辞書のキーとして文字列オブジェクトを使用することです。
キーとして他のオブジェクトを使用してもいいですが、各キーが辞書で使用するためにコピーされることを心に留めておき、そのため NSCopying をサポートしていなければなりません。ただし、キー値のコーディングを使用したい場合は、(キー値コーディングのプログラミング·ガイドを参照して詳細を学びましょう) 辞書オブジェクトの文字列キーを使用しなければなりません。
辞書の作成
次のように初期化、またはクラスファクトリ・メソッドを使用して辞書を作成できます。
- NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
-                       someObject, @"anObject",
-             @"Hello, World!", @"helloString",
-                                   @42, @"magicNumber",
-                         someValue, @"aValue",
-                                     nil];
dictionaryWithObjectsAndKeys: と initWithObjectsAndKeys: のメソッドでは、各オブジェクトは、そのキーの前に指定され、オブジェクトやキーのリストとキーが nil で終了する必要があります。
Objective-C は、辞書リテラルを作成するための簡潔な構文を提供しています。
- NSDictionary *dictionary = @{
-                           @"anObject" : someObject,
-                       @"helloString" : @"Hello, World!",
-                   @"magicNumber" : @42,
-                               @"aValue" : someValue
- };
辞書リテラルの場合、キーは、そのオブジェクトの前に指定され、オブジェクトやキーのリストの終りは nil でありません。
辞書を照会
辞書を作成した後、指定されたキーで格納されたオブジェクトのためそれを求めることができます。
NSNumber *storedNumber = [dictionary objectForKey:@"magicNumber"];
オブジェクトが見つからない場合は、 objectForKey: メソッドは nil を返します。
objectForKey: を使用する、より良いサブスクリプト構文もあります。
NSNumber *storedNumber = dictionary[@"magicNumber"];
辞書の可変性
作成した後、辞書からオブジェクトを追加または削除する必要がある場合は、NSMutableDictionary サブクラスを使用して下さい。
- [dictionary setObject:@"another string" forKey:@"secondString"];
- [dictionary removeObjectForKey:@"anObject"];
NSNull で nil を表す
Objective-C では nil は「オブジェクトがない」事を意味するので、このセクションで説明するコレクションクラスに nil を追加することはできません。オブジェクトがない事をコレクションで表したいなら、NSNull クラスを使用して下さい。
NSArray *array = @[ @"string", @42, [NSNull null] ];
NSNull 、Null メソッドでは、常に同じインスタンスを返します。このように振る舞うクラスは シングルトンクラス と呼ばれています。配列内のオブジェクトが以下のような共有 NSNull インスタンスと等しいかどうかを確認できます:
- for (id object in array) {
-         if (object == [NSNull null]) {
-                 NSLog(@"Found a null object");
-         }
- }
Foundation フレームワークは、ここで説明されているよりも多くの機能を含んでいますが、すぐに一つ一つの細部を知っている必要はありません。ファウンデーションについてもっと知りたい場合は、ファウンデーション・フレームワーク・リファレンス を見てみましょう。今は、カスタム・データクラスを書くことで ToDoList アプリを実装するのを続けるのに十分な情報をあなたは持っています。
前の章:デザインパターンを使用
次の章:カスタムクラスを書く