【たのしいCocoa】08_コレクション

「たのしいCocoaプログラミング[Leopard対応版]」を元に、要約メモしておきたいと思います。
コレクション
複数のオブジェクトをまとめておくためのクラスのことを、コレクションクラスと呼ぶ。
配列
NSArray と NSMutableArray
例えば、NSString のインスタンスをまとめておく配列は次のようになる。
1 | NSString* names[5]; |
配列の作成
1個のオブジェクトを指定して作成
1個だけオブジェクトを指定して配列を作る方法。arrayWithObject: というメソッドを使う。
NSArray
1 2 | + (id) arrayWithObject:(id)object オブジェクト object を指定して、インスタンスを作成する |
使用例は以下。
1 2 3 | // 文字列1つを含む配列を作る NSString* string = @"name"; NSArray* array = [NSArray arrayWithObject:string]; |
複数のオブジェクトを指定して作成
複数のオブジェクトを指定するには、arrayWithObjects: 、initWithObject: というメソッドを使う。
NSArray
1 2 3 | + (id) arrayWithObjects: (id) firstObj, ... - (id) initWithObjects: (id) firstObj, ... 複数のオブジェクトを指定して、インスタンスを作成する。引数の最後には nil を指定する。 |
このメソッドは可変変数を使う。複数指定した引数の最後には必ず nil を指定する。nil を渡すことで、オブジェクトの引数はここまで、という宣言になる。
1 2 3 4 | // 引数の文字列を指定して、配列を作成する NSArray* array; array = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; // array は、"A"、"B"、"C"を含む大きさ3の配列になる。 |
引数の最後の nil を忘れると、ほとんどの場合アプリケーションがクラッシュする。
配列の大きさ
配列の大きさを調べるには、count というメソッドを使う。
NSArray
1 2 | - (unsigned) count 配列に含まれる要素の数を取得する |
使用例は以下。
1 2 3 4 5 | // 配列を作る NSArray* array = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; // 配列の大きさを表示する NSLog(@"count is %d, [array count]); // count は、3になる |
インデックスを指定したオブジェクトの取得
配列の中にあるオブジェクトを取り出すためには、objectAtIndex: というメソッドを使う。
NSArray
1 2 | - (id) objectAtIndex:(unsigned)index インデックス index を指定して、要素を取得する |
例えば、3番目のオブジェクトを取り出すには以下のようになる。
1 2 3 4 5 6 7 | // 配列を作る NSArray* array = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; // 3番目のオブジェクトを取得する NSString* thirdObject = [array objectAtIndex:2]; NSLog(thirdObject); // thirdObject は、"C"になる |
インデックスが配列の大きさを超えてしまうと例外が発生してしまう。それを防ぐには、オブジェクトを取り出す前に配列の大きさをチェックする。
1 2 3 4 5 6 7 8 | // objectAtIndex: でアクセスする前に、count を使って配列の大きさをチェックする // ここでは2より大きい、つまり3以上あるかどうか調べている NSArray* array = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; int index = 2; if ([array count] > index) { NSString* thirdObject; thirdObject = [array objectAtIndex:index]; } |
objectAtIndex: と for 文を利用すれば、配列の中にあるすべてのオブジェクトにアクセスすることができる。
1 2 3 4 5 6 7 8 9 10 | // 配列を作る NSArray* array = [NSArrayWithObjects:@"A", @"B", @"C", nil]; // 配列の大きさだけ、 for ループを回す int i; for (i = 0; i < [array count]; i++) { // インデックスを指定して、オブジェクトを取り出す NSString* string = [array objectAtIndex:i]; NSLog(string); } |
for 文の中で、count メソッドを使って配列の大きさをチェックしている。実行すると i は0から2まで変化することになる。それぞれの値で objectAtIndex: を呼び出すから全てのオブジェクトを取り出すことができる。
NSEnumerator を使ったオブジェクトの取得
for 文を使う以外に、列挙子と呼ばれる考え方を使うものもある。
NSEnumerator
1 2 | - (id)nextObject 現在のオブジェクトの、次のオブジェクトを取得する |
NSEnumerator を取得したら、このメソッドを呼び続ける。そうして全てのオブジェクトを次々と取り出せる。
NSArray で NSEnumerator を利用する場合は、objectEnumerator というメソッドを使う。
NS Array
1 2 | - (NSEnumerator*)objectEnumerator 列挙子を取得する |
取得したら、while 文を使ってループを回ることになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 配列を作る NSArray* array = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; // 列挙子を取得する NSEnumerator* enumerator; enumerator = [array objectEnumerator]; // while 文を使って、NSEnumerator の nextObject を繰り返し呼び出す。 NSString* string; while (string = [enumerator nextObject]) { // 取り出した文字列に対して処理を行う NSLog(string); } |
nextObject メソッドを使ってオブジェクトを取り出して、それを string に代入している。その string の値が、while ループを続けるかどうかの条件になっている。値が入っていればループは続き、最後のオブジェクトになって nil が返ってくればループは終了する。
高速列挙を使ったオブジェクトの取得
1 2 3 4 5 6 7 8 | // 配列を作る NSArray* array = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; // 高速列挙を使って、オブジェクトにアクセスする for (NSString* string in array) { // 取り出した文字列に対して処理を行う NSLog(string); } |
for 文に対して拡張が行われていて、直接配列にアクセスすることができる。文法的には以下のようになる
1 2 3 | for (変数宣言 in オブジェクトの集合) { ... } |
for 文の中で変数の宣言を行い、in というキーワードを置く。その後にオブジェクトの集合となるクラスがくる。オブジェクトの集合としては NSArray などを指定することができる。高速列挙は、NSWnumerator を使うものと比べると、ソースコードの記述量が格段に少なくなる。
オブジェクトの追加と削除
空の配列を作成
空の配列を作っておいて、あとからオブジェクトを追加することもできる。
NSArray
1 2 | + (id)array 中身が空のインスタンスを作成する |
オブジェクトの追加
オブジェクトを追加するためのメソッドは、NSMutableArray で定義されている。
NSMutableArray
1 2 3 4 5 6 7 8 9 10 | - (void)addObject:(id)object オブジェクト object を追加する - (void)addObjectsFormArray:(NSArra*)array 配列 array に含まれている全てのオブジェクトを追加する - (void)insertObject:(id)object atIndex:(unsigned)Index オブジェクト object をインデックス index に追加する - (void)replaceObjectAtIndex:(unsigned)index withObject:(id)object インデックス index にあるオブジェクトを、オブジェクト object と置換する - (void)setArray:(NSArray*)array すべてのオブジェクトを、配列 array に含まれているオブジェクトと交換する |
インデックスを指定するものは、配列を越えると例外が発生してしまうので注意。使用例は以下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // 空配列を作る NSMutableArray* array = [NSmutableArray array]; // オブジェクトを追加する [array addObject:@"A"]; // 配列に含まれるオブジェクトを追加する NSArray* array1 = [NSArray arrayWithObjects:@"B", @"C", @"D", nil]; [array addObjectsFromArray:array1]; // オブジェクトを挿入する [array insertObjects:@"E" atIndex:0]; // オブジェクトを置き換える [array replaceObjectAtIndex:1 withObject:@"F"]; NSLog(@"%@", array); // 最終的な配列は、"E"、"F"、"B"、"C"、"D" |
オブジェクトの削除
NSMutableArray
1 2 3 4 5 6 7 8 9 10 11 12 | - (void)removeAllObjects すべてのオブジェクトを削除します - (void)removeLastObject 最後のオブジェクトを削除する - (void)removeObjectAtIndex:(unsigned)index インデックス index にあるオブジェクトを削除する - (void)removeObject:(id)object 配列に含まれるオブジェクトで、オブジェクト object と同じ値を持つものをすべて削除する - (void)remobeObjectIdentialTo:(id)object 配列に含まれるオブジェクトで、オブジェクト object と同じものをすべて削除する - (void)removeObjectsInArray:(NSArray*)array 配列に含まれるオブジェクトで、配列 array に含まれるオブジェクトと同じ値を持つものをすべて削除する |
辞書
辞書とは
あるオブジェクトを指定すると、それに関連づけられたオブジェクトを指定することができる。たとえば、ある Mac の情報をこのようにまとめておける。
1 | "CPU" => "Intel Core 2 Duo" |
CPU がキーで、Intel Core 2 Duo が値。
NSDictionary と NSMutableDictionary
Cocoa で辞書を実現するのは、変更できない辞書 NSDictionary と、変更できる辞書 NSMutableDictionary というクラス。
NSDictionary の作成
1つのキーの値のペアを指定して作成
NSDictionary
1 2 | + (id)dictionaryWithObject:(id)object forKey:(id)key 値 object とキー key を指定して、インスタンスを作成する |
使用例は以下。
1 2 3 | // キーと値のペアを指定して辞書を作る NSDictionary* dict; dict = [NSDictionaryWithObject:@"Core 2 Duo" forKey:@"CPU"]; |
複数のキーと値のペアを指定して作成
NSDictionary
1 2 3 4 5 6 | + (id)dictionaryWithObjects:(NSArray*)objects forKeys:(NSArray*)keys - (id)initWithObjects:(NSArray*)objects forKeys:(NSArray*)keys 値の配列 objects とキーの配列 keys を指定して、インスタンスを作成する + (id)dictionaryWithObjectsAndKeys:(id)firstObj, ... - (id)initWithObjectsAndKeys:(id)firstObj, ... 値とキーのペアを複数指定して、インスタンスを作成する。最後の引数は nil にする。 |
使用例は以下。
1 2 3 4 5 6 7 8 9 10 11 | // キーと値の配列を指定して辞書を作る NSArray* keys; NSArray* objects; NSDictionary* dict0; keys = [NSArray arrayWithObjects:@"CPU", @"Memory", @"Color", nil]; objects = [NSArray arrayWithObjects:"Core 2 Duo", @"2GB", @"Black", nil]; dict0 = [NSDictionary dictionaryWithObjects:ojects forKeys:keys]; // キーと値のペアを引数として指定して、辞書を作る NSDictionary* dict1; dict1 = [NSDictionary dictionaryWithObjectsAndKeys:@"Core 2 Duo", @"CPU", @"2GB", @"Memory", @"Black", @"Color", nil]; |
キーと値の取得
キーを指定して値を取得
作った辞書を引くためには、objectForKey: というメソッド。
NSDictionary
1 2 | - (id)objectForKey:(id)key キー key を指定して、関連づけられている値を取得する。対応する値がない時は nil を返す。 |
使用例は以下。
1 2 3 4 5 6 | // 辞書を作る NSDictionary* dict = [NSDictionary dictionaryWithOjectAndKeys:@"Core 2 Duo", @"CPU", @"2GB", @"Memory", @"Black", @"Color", nil]; // キー"CPU"を取得して、対応する値を取り出す NSString* cpuType = [dict objectForKey:@"CPU"]; // cpuTypeには、"Core 2 Duo"が入る |
すべてのキー、値を取得
辞書に含まれるすべてのキーと値を取得することもできる。
NSDictionary
1 2 3 4 5 6 7 8 | - (NSArray*)allkeys すべてのキーを配列の形で取得する - (NSEnumerator*)keyEnumerator すべてのキーにアクセスする列挙子を取得する - (NSArray*)allValues すべての値を配列の形で取得する - (NSEnumerator*)objectEnumerator すべての値にアクセスする列挙子を取得する |
使用例は以下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 辞書を作る NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:@"Core 2 Duo", @"CPU", @"2GB", @"Memory", @"Black", @"Color" nil]; // キーのための列挙子を取得する NSEnumerator* enumerator = [dict keyEnumerator]; // すべてのキーを取り出す NSString* key; while (key = [enumerator nextObject]) { // キーに対する値を取得する NSString* value; value = [dict objectForKey:key]; // キーと値のペアに対する処理 NSLog(@"key is %@, value is %@", key, value); } |
まず keyEnumerator メソッドで列挙子を取得して、while 文を回す。これでキーを順々に取り出すことができる。
キーと値の追加と削除
空の辞書を作成
NSDictionary
1 2 | + (id)dictionary 中身が空の辞書を作成する |
キーと値のペアを追加
NSMutableDictionary
1 | - (void)setObject:(id)object forKey:(id)key |
どちらの値も nil にならないように気をつける。使用例は以下。
1 2 3 4 5 6 7 | // 空の辞書を作る NSMutableDictionary* dict = [NSMutableDictionary dictionary]; // キーと値をペアで追加する [dict setObject:@"Core 2 Duo" forKey:@"CPU"; [dict setObject:@"2GB" forKey:@"Memory"; [dict setObject:@"Black" forKey:@"Color"; |
キーと値のペアを削除
NSMutableDictionary
1 2 3 4 5 6 | - (void)removeAllObjects すべてのキーと値のペアを削除する - (void)removeObjectForKey:(id)key キー key と、それに関連づけられているオブジェクトを削除する - (void)removeObjectsForKeys:(NSArray*)keyArray キーの配列 keyArray と、それに含まれているキーに関連づけられているオブジェクトを削除する |
ラッパークラス
ラッパークラスとは
NSArray と NSDictionary という2つのコレクションクラスに入れることができるのは、オブジェクトになる。整数や小数や理論値などの数値を入れるには、int や float や BOOL といった基本型を使う。ラッパークラスでこれらの基本型を包んで、オブジェクトとして扱えるようにするクラス。
NSNumber
基本型からインスタンスを作るためのメソッド。
NSNumber
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | + (id)numberWithBool:(BOOL)value - (id)initWithBool:(BOOL)value 理論値型の値 value を指定してインスタンスを作成する + (id)numberWithChar:(char)value - (id)initWithChar:(char)value + (id)numberWithUnsignedChar:(unsigned char)value - (id)initWithUnsignedChar:(unsigned char)value 文字型の値 value を指定してインスタンスを作成する + (id)numberWithInt:(int)value - (id)initWithInt:(int)value + (id)numberWithUnsignedInt:(unsigned int)value - (id)initWithUnsignedInt:(unsigned int)value + (id)numberWithLong:(long)value - (id)initWithLong:(long)value + (id)numberWithUnsignedLong:(unsigned long)value - (id)initWithUnsignedLong:(unsigned long)value 整数型の値 value を指定して、インスタンスを作成する + (id)numberWithFloat:(float)value - (id)initWithFloat:(float)value + (id)numberWithDouble:(double)value - (id)initWithDoouble:(double)value 小数型の値 value を指定してインスタンスを作成する |
取り出す方のメソッドは以下。
NSNumber
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | - (BOOL)boolvalue 論理値型の値を取得する - (char)charValue - (unsigned char)unsingnedCharValue 文字型の値を取得する - (int)intValue - (unsingned int)unsingnedIntValue - (long)longValue - (unsigned long)unsignedLongValue 整数型の値を取得す - (float)floatValur - (double)doubleValue 小数型の値を取得する - (NSString*)stringValue 値を文字列にしたものを取得する |
これらの値を取り出すメソッドは、インスタンスを作成したときの基本型によらず、どの型としてでも取り出すことができる。また、stringValue を使うと、今の値を文字列として取り出すことができる。
1 2 3 4 5 6 7 8 9 10 | // 空の文字列を作る NSMUtableArray* array = [NSMutableArray array]; int i; for (i=0; i<0; i++) { // 整数型を指定して、NSNumber クラスを作る NSNumber* number = [NSNumber numberWithInt:i]; // 配列に追加する [array addObject:number]; } |
オブジェクトの同等性と同値性
同じ値を持つオブジェクト
異なるインスタンスでありながら同じ値を持っていることを同値である、インスタンス自体が同じであることを同等であるという。
同値性と同等性の判定
同等性のチェックは比較演算子 == を使う。
1 2 3 4 5 6 7 | // オブジェクトの同等性をチェックする id objectA, objectB; objectA = @"stringA"; objectB = objectA; if (objectA == objectB) { // objectA と objectB は同等 } |
同値性は isEqual: というメソッドを使う。
NSObject
1 2 | - (BOOL)isEqual:(id)object オブジェクト object が、このインスタンスと等しいかを返す。 |
使用例は以下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // NSArray のインスタンスを2つ作る NSArray* array0 = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; NSArray* array1 = [NSArray arrayWithObjects:@"A", @"B", @"C", nil]; // array0 と array1 の同等性を調べる BOOL result; result = array0 == array1; NSLog(@"array == array1, %d, result); // result は NO になる // array0 とarray1 の同値性を調べる result = [array0 isEqual:array1]; NSLog(@"[array0 isEqual:array1], %d, result); // result は YES になる |
同等ではないが同値であるということになる。
コレクションクラスと参照カウンタ
コレクションクラスにオブジェクトを追加すると、コレクションクラスがそのオブジェクトを保持することになり、参照カウンタが1上がる。
NSArray と参照カウンタ
NSArray が開放されるときには、そこに登録されているオブジェクト全てに release が送られる。一度 NSArray に入れれば、そのオブジェクトを保持する必要があったとしても release しても構わない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 空の配列を作成する // この array という変数は、インスタンス変数として宣言されているものとする array = [NSMutableArray array]; // NSString インスタンスを作る NSString* string = [[NSString alloc] iniWithCString:"New String"encoding:NSASCIIStringEncoding]; // この時点で参照カウンタは1 // 配列に追加する [array addObject:string]; // string の retain メソッドが呼び出される。参照カウンタは2になる // string の release メソッドを呼び出す [string release]; // 参照カウンタは1になる // これで NSArray がこのオブジェクトの開放に責任を持つことになる |
NSDictionary と参照カウンタ
値に関しては NSArray と同じ。NSDictionary に追加された時点で retain される。キーに関しては少し違って、NSDictionary に追加しようとすると、キーのオブジェクトはコピーされて、コピーされた方が追加される。
