


NSMutableArray *myMutableArray = [NSMutableArray arrayWithArray:myArray];
一般に、配列の1つをNSArray または NSMutableArrayにメッセージを送ることで配列をインスタンス化する。
配列は引数条件をパスした要素を含む配列を返す。
lblArray=[[NSMutableArray alloc]init];
ループ
{
UILabel *lbl=[[UILabel alloc]init]; // lblの実体が確保される
~
[lblArray addObject:lbl]; // lblはretainされる
[lbl release]; // 実開放はlblArrayのrelease時
}
この例の場合、配列lblArrayに加えられた個別のオブジェクトlblはaddObject:した時点でretainされる。
そのため、その直後にreleaseメッセージを発行してもその場では解放されない。
配列lblArrayがreleaseされるとき、要素になっている全てのlblにreleaseが発行され、
そこで初めて実解放される。
| addObject: | 追加 |
| insertObject:atIndex: | 挿入 |
| removeLastObject | 最後の要素の削除 |
| removeObjectAtIndex: | 指定位置の要素を削除 |
| replaceObjectAtIndex:withObject: | 指定位置の要素を置き換え |
NSString *someString=[arrayOfStrings objectAtIndex: 2];
NSArrayのメソッド objectEnumerator と reverseObjectEnumerator は配列要素への連続的なアクセスを提供する。
この2つは取り出す方向だけが違う。| subarrayWithRange: | 配列の一部を引き抜いてサブセットを作る |
| componentsJoinedByString: | 配列要素がNSStringの場合、それを1つの文字列に連結する |
| isEqualToArray: | 2つの配列を比較する |
| firstObjectCommonWithArray: | レシーバーの配列の要素の中で、引数の配列と一致する最初の要素を返す |
| arrayByAddingObjectsFromArray: | 既存の配列の後ろに別配列を結合して新規の配列を作成する |
| arrayByAddingObject: | 既存の配列の後ろに1つの要素を結合して新規の配列を作成する |
リスト 4 配列中オブジェクトの検索
#define yes0 @"yes"
#define yes1 @"YES"
NSString *yes2 = [NSString stringWithFormat:@"%@", yes1];
NSArray *yesArray = [NSArray arrayWithObjects: yes0, yes1, yes2, nil];
NSUInteger index;
index = [yesArray indexOfObject:yes2]; // index is 1
index = [yesArray indexOfObjectIdenticalTo:yes2]; // index is 2
配列のソート
リスト 5 辞書配列の生成とソート
// キー名の定義
#define LAST @"lastName"
#define FIRST @"firstName"
//
// 辞書配列の生成
NSDictionary *dict;
NSMutableArray *array = [NSMutableArray array];
//
dict = [NSDictionary dictionaryWithObjectsAndKeys: @"Jo" , FIRST, @"Smith" , LAST, nil];
[array addObject:dict];
dict = [NSDictionary dictionaryWithObjectsAndKeys: @"Joe" , FIRST, @"Smith" , LAST, nil];
[array addObject:dict];
dict = [NSDictionary dictionaryWithObjectsAndKeys: @"Joe" , FIRST, @"Smythe", LAST, nil];
[array addObject:dict];
dict = [NSDictionary dictionaryWithObjectsAndKeys: @"Joanne", FIRST, @"Smith" , LAST, nil];
[array addObject:dict];
dict = [NSDictionary dictionaryWithObjectsAndKeys: @"Robert", FIRST, @"Jones" , LAST, nil];
[array addObject:dict];
//
// 姓/名それぞれでソートするためのNSSortDescriptorを作成する
NSSortDescriptor *lastDescriptor =
[[[NSSortDescriptor alloc] initWithKey:LAST ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
NSSortDescriptor *firstDescriptor =
[[[NSSortDescriptor alloc] initWithKey:FIRST ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
// 配列内容を姓/名順にソートする
NSArray *descriptors = [NSArray arrayWithObjects:lastDescriptor, firstDescriptor, nil]; // ソート順に入れる
NSArray *sortedArray = [array sortedArrayUsingDescriptors:descriptors];
リスト6に示すように、名前~姓順のソート順を変更することも簡単である。
リスト 6 名前~姓順のソート
NSSortDescriptor *lastDescriptor =
[[[NSSortDescriptor alloc] initWithKey:LAST ascending:NO selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
NSSortDescriptor *firstDescriptor =
[[[NSSortDescriptor alloc] initWithKey:FIRST ascending:NO selector:@selector(localizedCaseInsensitiveCompare:)] autorelease];
NSArray *descriptors = [NSArray arrayWithObjects:firstDescriptor, lastDescriptor, nil]; // ソート順に入れる
NSArray *sortedArray = [array sortedArrayUsingDescriptors:descriptors];
リスト 7 関数を用いたソート;柔軟でない
NSInteger lastNameFirstNameSort(id person1, id person2, void *reverse)
{
NSString *name1 = [person1 valueForKey:LAST];
NSString *name2 = [person2 valueForKey:LAST];
NSComparisonResult comparison = [name1 localizedCaseInsensitiveCompare:name2];
if (comparison == NSOrderedSame) {
name1 = [person1 valueForKey:FIRST];
name2 = [person2 valueForKey:FIRST];
comparison = [name1 localizedCaseInsensitiveCompare:name2];
}
if (*(BOOL *)reverse == YES) {
return 0 - comparison;
}
return comparison;
}
BOOL reverseSort = YES;
NSArray *sortedArray = [array sortedArrayUsingFunction:lastNameFirstNameSort context:&reverseSort];
ブロックによるソート
リスト 8 ブロックによる配列の独自ソート
NSArray *sortedArray = [配列 sortedArrayUsingComparator:
^(id obj1, id obj2)
{
if ([obj1 integerValue] > [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
if ([obj1 integerValue] < [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedAscending;
}
// 一致
return (NSComparisonResult)NSOrderedSame;
}
];
関数とセレクターによるソート
リスト 9 セレクターと関数によるソート
NSInteger alphabeticSort(id string1, id string2, void *reverse)
{
if (*(BOOL *)reverse == YES) {
return [string2 localizedCaseInsensitiveCompare:string1];
}
return [string1 localizedCaseInsensitiveCompare:string2];
}
// 注: anArray はソート済み
NSMutableArray *anArray = [NSMutableArray arrayWithObjects:
@"aa", @"ab", @"ac", @"ad", @"ae", @"af", @"ag",
@"ah", @"ai", @"aj", @"ak", @"al", @"am", @"an", @"ao", @"ap", @"aq", @"ar", @"as", @"at",
@"au", @"av", @"aw", @"ax", @"ay", @"az", @"ba", @"bb", @"bc", @"bd", @"bf", @"bg", @"bh",
@"bi", @"bj", @"bk", @"bl", @"bm", @"bn", @"bo", @"bp", @"bq", @"br", @"bs", @"bt", @"bu",
@"bv", @"bw", @"bx", @"by", @"bz", @"ca", @"cb", @"cc", @"cd", @"ce", @"cf", @"cg", @"ch",
@"ci", @"cj", @"ck", @"cl", @"cm", @"cn", @"co", @"cp", @"cq", @"cr", @"cs", @"ct", @"cu",
@"cv", @"cw", @"cx", @"cy", @"cz", nil];
NSData *sortedArrayHint = [anArray sortedArrayHint]; // ソート済み配列の情報を得ておく
[anArray insertObject:@"be" atIndex:5]; // 追加する
// セレクターによるソート
NSArray *sortedArray;
sortedArray = [anArray sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
// 関数によるソート
BOOL reverseSort = NO;
sortedArray = [anArray sortedArrayUsingFunction:alphabeticSort context:&reverseSort];
// ヒントによるソート
sortedArray = [anArray sortedArrayUsingFunction:alphabeticSort context:&reverseSort hint:sortedArrayHint];
|
重要: ローカライズが必要な文字列をソートするときは、ソート関数における比較に考慮が必要である。 別の言語または文脈では、ソートされた配列の正しい順序は、異なることがありえる。 |
リスト 10 属性による配列のふるいがけ NSMutableArray *array = [NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melissa", nil]; NSPredicate *bPredicate = [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"]; // 'b'または'B'で始まる物 NSArray *beginWithB = [array filteredArrayUsingPredicate:bPredicate]; // beginWithB は { @"Bill", @"Ben" }を含む NSPredicate *sPredicate = [NSPredicate predicateWithFormat:@"SELF contains[c] 's'"]; // 's'または'S'を含むも物 [array filterUsingPredicate:sPredicate]; // arrayは { @"Chris", @"Melissa" } を含むNSIndexSet オブジェクトを使っても配列のふるいがけは出来る。 NSArray は objectsAtIndexes:を提供し、これはインデックスセットが提供する要素番号群のオブジェクトを含む新しい配列を返す。 NSMutableArray には removeObjectsAtIndexes:が追加され、これはインデックスセットを使って配列内でふるいがけをする。

NSMutableDictionary *myMutableDictionary = [NSMutableDictionary dictionaryWithDictionary: myDictionary];
一般にNSDictionary または NSMutableDictionary クラスに1つの辞書にメッセージを送ることで辞書をインスタンス化する。
辞書~メッセージは引数として渡すキーと値を含む辞書を返す。
辞書に追加する値のオブジェクトは(initWithDictionary:copyItems:でYESを指定しない限り)深くコピーされない。
リスト 1 削除後のオブジェクトへのアクセスは危険 id anObject = [aDictionary objectForKey:theKey]; [aDictionary removeObjectForKey:theKey]; // theKeyを持つオブジェクトにreleaseが発行される [anObject someMessage]; // クラッシュするかもこの可能性を回避するために、リスト2で例示されるように、それを取り除く前にオブジェクトを保持する。
リスト 2 削除する前にオブジェクトの所有権を保持する id anObject = [[aDictionary objectForKey:theKey] retain]; // さらにもう1段保持を掛ける [aDictionary removeObjectForKey:theKey]; [anObject someMessage]; // 使い終わった後に、anObjectにreleaseメッセージを送ること可変辞書にオブジェクトを追加することは比較的直接である。
リスト 3 辞書にオブジェクトを追加する #define LAST @"lastName" #define FIRST @"firstName" NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys: @"Jo", FIRST, @"Smith", LAST, nil]; #define MIDDLE @"middleInitial" [dict setObject: @"M" forKey:MIDDLE];他の辞書からエントリーを追加するにはaddEntriesFromDictionary: インスタンスメソッドを使うことも出来る。
リスト 4 他の辞書からエントリを追加する
#define LAST @"lastName"
#define FIRST @"firstName"
#define SUFFIX @"suffix"
#define TITLE @"title"
// 値 キー
NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys: @"Jo" , FIRST ,
@"Smith", LAST , // ←これが
nil];
NSDictionary *newDict=[NSDictionary dictionaryWithObjectsAndKeys: @"Jones", LAST , // ←これで置換される
@"Hon." , TITLE ,
@"J.D." , SUFFIX,
nil];
[dict addEntriesFromDictionary: newDict];
リスト 5 値による辞書キーのソート
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
// 値 キー
[NSNumber numberWithInt:63], @"Mathematics",
[NSNumber numberWithInt:72], @"English",
[NSNumber numberWithInt:55], @"History",
[NSNumber numberWithInt:49], @"Geography",
nil];
NSArray *sortedKeysArray = [dict keysSortedByValueUsingSelector:@selector(compare:)]; // compare:は比較関数
sortedKeysArray は Geography, History, Mathematics, English の順になる。
リスト 6 ブロック構文は辞書のカスタムソートを容易にする
NSArray *blockSortedKeys = [dict keysSortedByValueUsingComparator:
^(id obj1, id obj2)
{
if ([obj1 integerValue] > [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
if ([obj1 integerValue] < [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}
];

| initWithSet: setWithSet: | 他のセットからインスタンスを生成する |
| addObject: | セットへの単一オブジェクトの追加 |
| addObjectsFromArray: | 指定配列から全オブジェクトの追加 |
| unionSet: | 他のセットから、レシーバーに存在しないすべてのオブジェクトを加える |
| intersectSet: | 他のセット内に存在しない全てのオブジェクトを削除する |
| removeAllObjects | セットから全てのオブジェクトを削除する |
| removeObject: | セットから特定のオブジェクトを削除する |
| minusSet: | 他のセット内にあるオブジェクトを全て削除する |
| unionSet: | それらがすでに存在するとしても、他のセットから全てのオブジェクトを追加する |
| intersectSet: | 他のセットにない全てのオブジェクトを削除する。 同じオブジェクトの複数のインスタンスがどちらのセットにでもあるならば、 結果として出来るセットはより少ない回数のインスタンスのオブジェクトを含む。 |
| minusSet | 他のセットにある全てのオブジェクトを削除する。 あるオブジェクトが1回以上counted セットに現れるなら、 それは、それの1つのインスタンスを取り除くだけである。 |
リスト 1 オブジェクト削除後のアクセスは危険 id anObject = [aSet anyObject]; [aSet removeObject:anObject]; // anObjectにreleaseを発行する [anObject someMessage]; // クラッシュするかもこの可能性を回避するために、リスト2で例示されるように、それを取り除く前にオブジェクトを保持する。
リスト 2 削除する前にオブジェクトの所有権を保持する id anObject = [[aSet anyObject] retain]; // さらにもう1段保持を掛ける [aSet removeObject:anObject]; [anObject someMessage]; // 使い終わった後に、anObjectにreleaseメッセージを送ることセットの利用
| allObjects | セット中の全オブジェクトを含む配列を返す |
| anyObject | セット中のいくつかのオブジェクトを返す(オブジェクトはランダムではなく都合の良い物が選ばれる) |
| count | 現在のセット内のオブジェクト数を返す |
| member: | セット内で指定オブジェクトに一致するオブジェクトを返す |
| intersectsSet: | 2つのセットが少なくとも1つのオブジェクトを共有するかどうか調べる |
| isEqualToSet: | 2つのセットが等しいかどうか調べる |
| isSubsetOfSet: | セットに含まれるオブジェクトの全てがもう一セットでも存在するかどうか調べる |

NSIndexSet *myImmutableIndexes=[[NSIndexSet alloc]initWithIndexSet: myIndexes];
インデックスセットは、initWithIndex:またはinitWithIndexesInRange:によって、1つの要素番号または要素番号の範囲から初期化することが出来る。
リスト 1 可変インデックスセットへの要素番号群の追加
[myDisjointIndexes addIndexesInRange: NSMakeRange(1,2)];
[myDisjointIndexes addIndexesInRange: NSMakeRange(5,3)];
[myDisjointIndexes addIndex: 10];
リスト 2 インデックスセットを介した前方アクセス
NSUInteger index=[anIndexSet firstIndex];
while(index != NSNotFound) {
NSLog(@" %@",[anArray objectAtIndex:index]);
index=[anIndexSet indexGreaterThanIndex:index];
}
時として、インデックスセットを後方からアクセスする必要があるかも知れない。
たとえば、NSMutableArrayオブジェクトから選択的にインデックスからオブジェクトを取り除きたい時など。
この時はリスト3のように後方から反復出来る。
リスト 3 インデックスセットを通した後方アクセス
NSUInteger index=[anIndexSet lastIndex];
while(index != NSNotFound) {
if ([[aMutableArray objectAtIndex:index] isEqualToString:@"G"]){
[aMutableArray removeObjectAtIndex:index];
}
index=[anIndexSet indexLessThanIndex:index];
}
インデックスセットによって参照されるオブジェクトを選択的に取り除きたい場合だけ、
上記の方法が使われなければならない。
リスト 4 ブロック構文を使って配列からインデックスセットを作成する
NSIndexSet *lessThan20=[someArray indexesOfObjectsPassingTest:
^(id obj, NSUInteger index, BOOL *stop)
{
if ([obj isLessThan:[NSNumber numberWithInt:20]]){
return YES;
}
return NO;
}
];
インデックスセットは配列のブロック列挙を使うことも出来る。
インデックスセットに含まれる配列のインデックスだけを列挙するためは
enumerateObjectsAtIndexes:options:usingBlock: メソッドを使う。
リスト 5 複数の配列にアクセスするインデックスセットを列挙する
[anIndexSet enumerateIndexesUsingBlock:
^(NSUInteger idx, BOOL *stop)
{
if ([[firstArray objectAtIndex:idx]isEqual:[secondArray objectAtIndex:idx]]){
NSLog(@"Objects at %i Equal",idx);
}
}
];

リスト 1 配列からインデックスパスを作成する
NSUInteger integerArray[]={0,0,1,1,2};
NSIndexPath *aPath=[[NSIndexPath alloc]initWithIndexes:integerArray length:(sizeof(integerArray)/sizeof(NSUInteger))];

リスト 1 浅いコピーの作成
NSArray *shallowCopyArray=[someArray copyWithZone:nil];
NSDictionary *shallowCopyDict=[[NSDictionary alloc]initWithDictionary:someDictionary copyItems:NO];
リスト 2 深いコピーの作成
NSArray *deepCopyArray=[[NSArray alloc]initWithArray:someArray copyItems:YES];
| copyWithZone: | 表面レベルの不変を作成する。すべてのより深いレベルは、それらが以前持った可変性を持つ。 |
| initWithArray:copyItems: | 第2引数=NO は、クラスに与えられた表面レベルの可変性を持つ。 すべてのより深いレベルは、それらが以前持った可変性を持つ。 |
| initWithArray:copyItems: | 第2引数=YESは次のレベルは不変で、より深いレベルは、それらが以前持った可変性を持つ。 |
リスト 1 辞書における高速列挙の利用
// 配列の場合
for (NSString *要素 in someArray) {
NSLog(@"要素: %@", 要素);
}
// 辞書の場合
NSString *キー;
for (キー in someDictionary){
NSLog(@"Key: %@, Value %@", キー, [someDictionary objectForKey: キー]);
}
リスト 2 配列のブロック列挙
NSArray *anArray=[NSArray arrayWithObjects:@"A", @"B", @"D",@"M",nil];
NSString *string=@"c";
//
[anArray enumerateObjectsUsingBlock:
^(id obj, NSUInteger index, BOOL *stop)
{
if ([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame){
NSLog(@"Object Found: %@ at index: %i",obj, index);
*stop=YES;
}
}
];
NSSet オブジェクトに対してはリスト 3のようなコードにする。
リスト 3 セットに対するブロック列挙
NSSet *aSet=[NSSet setWithObjects: @"X", @"Y", @"Z", @"Pi", nil];
NSString *aString=@"z";
//
[aSet enumerateObjectsUsingBlock:
^(id obj, BOOL *stop)
{
if ([obj localizedCaseInsensitiveCompare:aString]==NSOrderedSame){
NSLog(@"Object Found: %@", obj);
*stop=YES;
}
}
];
NSArray 列挙においては、要素番号引数は、並列の列挙に役立つ。
この引数がない場合、要素番号にアクセスする唯一の方法は、能率の悪いindexOfObject:メソッドを使うことである。
リスト 4 辞書の列挙とオブジェクトの削除
NSMutableDictionary *myMutableDictionary = ... ;
NSMutableArray *keysToDeleteArray = [NSMutableArray arrayWithCapacity:[myMutableDictionary count]];
NSString *aKey;
//
NSEnumerator *keyEnumerator = [myMutableDictionary keyEnumerator];
while (aKey = [keyEnumerator nextObject]) {
if ( キーまたは値のテスト基準 ) {
[keysToDeleteArray addObject:aKey];
}
}
// 変更を反映する
[myMutableDictionary removeObjectsForKeys:keysToDeleteArray];
そうだったのか。なんか、objectEnumeratorのループ中に書き換えた記述をしたことがあったような、無かったような。
ビューを配列から取り出してプロパティーを変更するとか。
アドレスさえ変更してなければ良いのか?