NSArray, NSMutableArrayについての覚え書き

Last-modified: 2014-01-10 (金) 15:49:02

NSArray

初期化

リテラル記法

NSArray *array = @[@"abc", @"def", @"ghi", @"jkl"];
NSLog(@"%@", array);
NSLog(@"count: %ld", array.count);
NSLog(@"  0: %@", array[0]);
NSLog(@"  1: %@", array[1]);
NSLog(@"  2: %@", array[2]);
NSLog(@"  3: %@", array[3]);

変数を使ったリテラル記法

// リテラル記法は、変数を並べて書ける
NSString *a = @"こんにちわ";
NSString *b = @"おやすみなさい";
NSArray *array2 = @[a, b];
NSLog(@"%@", array2);

ネストした配列

NSArray *array3 = @[@"ABC", @[@"GHI", @"JKL"], @"DEF",@"こんにちわ"];
for (int i = 0; i < array3.count; i++) {
	NSLog(@"%d: %@", i, array3[i]);
}

浅いコピー

// flag がYESのときに、各要素をコピーして初期化
BOOL flag = YES;
NSArray *array5 = [[NSArray alloc] arrayWithArray:array3 copyItems:flag];
NSLog(@"copied: %@", array5);
NSLog(@"address: %p vs %p", array3[0], array5[0]);

アクセス

NSArray *array = @[@"abc", @"def", @"ghi", @"jkl"];
NSLog(@"original array: %@", array);

要素数

NSLog(@"count: %ld", array.count);

要素の位置を取得

NSString *anObject = @"ghi";
NSUInteger index = NSNotFound;
index = [array indexOfObject:anObject];
if (index != NSNotFound) {
	NSLog(@"%@ found at %ld", anObject, index);
} else {
	NSLog(@"%@ not found", anObject);
}

要素を持っているか?

BOOL doesContainTheObject = NO;
doesContainTheObject = [array containsObject:@"def"];
NSLog(@"Does contain? %@", doesContainTheObject ? @"YES!" : @"NO.");

要素の取り出し

for (NSUInteger ui = 0 ; ui < array.count; ui++) {
	NSLog(@"index %lu: %@", (unsigned long)ui, [array objectAtIndex:ui]);
}

最後の要素

// レンジの表す範囲のオブジェクトを、Cの配列へコピー。その配列の宣言に注目。
void *anObject1;
anObject1 = (__bridge void *)([array lastObject]);
NSLog(@"last object: %@", anObject1);

NSRange の範囲にある配列を取り出す

NSRange aRange = NSMakeRange(1, 2);
// ただのaBuffer単数ではダメで、複数見つかる可能性があるから、配列で渡す。
__unsafe_unretained id aBuffer[ sizeof(id) * aRange.length];
[array getObjects:aBuffer range:aRange];
for (int i = 0; i < aRange.length; i++ ) {
	NSLog(@"objects: %@", aBuffer[i]);
}
NSRange aRange2 = NSMakeRange(0, 3);
	NSLog(@"sub-array: %@", [array subarrayWithRange:aRange2]);
}

配列の比較、追加

配列同士が完全一致

// 格納している要素が同じで、同じインデックス位置にある要素が同じである。
NSArray *array1 = @[@"abc", @"def", @"ghi", @"jkl"];
NSArray *array2 = @[@"abc", @"def", @"ghi", @"jkl"];
NSArray *array3 = @[@"abc", @"def", @"GHI", @"jkl"];
BOOL areEqual;
areEqual = [array1 isEqualToArray: array2];
	NSLog(@"1 and 2 are equal? %@", areEqual ? @"YES!" : @"No.");
areEqual = [array1 isEqualToArray: array3];
	NSLog(@"1 and 3 are equal? %@", areEqual ? @"YES!" : @"No.");

2つの配列の和集合で、最初に見つかったオブジェクト

NSArray *array4 = @[@"JKL", @"ghi"];
__unsafe_unretained id firstObject;
// ここが難しかった。
//得られるのは1つのオブジェクトだから、単数(配列ではない)オブジェクト。
firstObject = [array1 firstObjectCommonWithArray:array4];
NSLog(@"first object: %@", firstObject);

新たな要素の追加した新しい配列

 NSLog(@"%@", [array1 arrayByAddingObject: @"123"]);
 NSLog(@"%@", [array1 arrayByAddingObjectsFromArray:@[@"123", @"456"]]);
 NSLog(@"%@", [@[@"123", @"456"] arrayByAddingObjectsFromArray:array1]);

ソート

セレクタを用いたソート

NSLog(@"sorted by selector(compare:): %@",
	[anArray sortedArrayUsingSelector:@selector(compare:)] );

関数(ポインタ)を用いて、ソート

{ // 関数の定義。ブロックの外で定義する。
NSComparisonResult compareFunction
	(__strong id leftObj, __strong id rightObj, void *aContext)
{
    NSString *leftString = leftObj;
    NSString *rightString = rightObj;
    NSUInteger lengthOfLeftString = leftString.length;
    NSUInteger lengthOfRightString = rightString.length;
    if ( lengthOfLeftString < lengthOfRightString) {
        return NSOrderedAscending;
    } else if ( lengthOfLeftString > lengthOfRightString ) {
        return NSOrderedDescending;
    } else {
        // same length
        // compare each character step by step
        for (int i = 0 ; i <= lengthOfRightString; i++ ) {
            unichar leftChar = [leftString characterAtIndex:i];
            unichar rightChar = [rightString characterAtIndex:i];
            if (leftChar < rightChar ) {
                return NSOrderedAscending;
            } else if ( leftChar > rightChar ) {
                return NSOrderedDescending;
            } // if ends
        } // for ends
    } // if ends
    return NSOrderedSame;
}
//
NSComparisonResult (*compareFunction)(__strong id, __strong id, void *);
void *aContext = NULL;
// 関数への第三引数、任意。これを使って比較動作を細かく設定できる、いわばパラメータ。
NSArray *sortedArray2
	= [anArray sortedArrayUsingFunction:compareFunction context:aContext];
NSLog(@"sorted by C-type function:");
for (NSString *aStr in sortedArray2) {
	NSLog(@"  %@", aStr);
}

ブロック記法を用いたソート

NSArray *anArray = @[@"098", @"245", @"678"];
NSArray *sortedArray = [anArray sortedArrayUsingComparator:
	^(NSString *leftStr, NSString *rightStr) {
 		NSUInteger leftLength = leftStr.length;
		NSUInteger rightLength = rightStr.length;
		if (leftLength > rightLength) {
			return NSOrderedDescending;
		} else if (leftLength < rightLength ) {
			return NSOrderedAscending;
		} else {
			for (int i = 0 ; i <= leftLength ; i++ ) {
				unichar leftChar = [leftStr characterAtIndex:i];
				unichar rightChar = [rightStr characterAtIndex:i];
				if (leftChar > rightChar ) {
					return NSOrderedDescending;
				} else if ( leftChar < rightChar ) {
					return NSOrderedAscending;
				}
			}
		}
		return NSOrderedSame;
	} ];
NSLog(@"sorted by block Comparator:");
for (NSString *aStr in sortedArray) {
	NSLog(@"  %@", aStr);
}

要素へメッセージの送信

すべてへ一斉送信

[anArray makeObjectsPerformSelector:@selector(description)];

引数を与えて

@interface NSMutableString (categoryExtensions)
- (void) addStringAtTail:(NSString *) aTailString;
@end
@implementation NSMutableString (categoryExtensions)
- (void) addStringAtTail:(NSString *) aTailString {
    [self appendString:aTailString];
}
// 同じく、NSArrayのメソッド追加
//NSStringの要素を持つ配列をNSLog()へ放り込むと、文字化け。
//ちゃんと文字が出力されるように、メソッドをカテゴリで追加。
@interface NSArray (categoryExtensions)
- (void)myPrintComponents;
@end
@implementation NSArray (categoryExtensions)
- (void)myPrintComponents {
	NSArray *anArray = self;
	for (id anObj in anArray) {
		NSLog(@"  %@", [anObj description]);
	}
}
@end
//配列の初期化
NSArray *anArray = @[
	[NSMutableString stringWithString:@"air"],
	[NSMutableString stringWithString:@"123"],
	[NSMutableString stringWithString:@"あいう"],
	[NSMutableString stringWithString:@"幸せ"],
	[NSMutableString stringWithString:@"*&^"]
];
NSString *ext = @".jpg";
[anArray makeObjectsPerformSelector:@selector(addStringAtTail:) withObject:ext];
[anArray myPrintComponents];

ブロックを用いて、全ての要素へアクセス

[anArray enumerateObjectsUsingBlock:
	^(NSString *str, NSUInteger index, BOOL *stop)
		 {
			NSLog(@"str: %@ (%lu)", str, (unsigned long)index);
			if (str.length >= 3) {
				*stop = YES;
			} // if ends
		} // block ends
]; // message ends

ファイル入出力

プロパティ形式で書き出し

BOOL isSuccess;
isSuccess = [anArray writeToFile:filePathString atomically:YES];
NSLog(@"write to file: %@", isSuccess ? @"Yes, successful!" : @"No, failure...");

プロパティ形式で保存されたファイルから初期化。

NSArray *anArrayFromPlist = [NSArray arrayWithContentsOfFile:filePathString];

結合して、文字列を生成

NSString *aSeparator = @"/";
NSString *aJoinedString = [anArray componentsJoinedByString:aSeparator];
NSString *aJoinedHeadingSlash = [@[@"/", anArray] componentsJoinedByString:anSeparator];
// これをするなら、NSURLを使おう。

指定する拡張子を持つNSStringの要素を抽出

// 引数の文字列配列は、拡張子群を表す。
// 格納要素で、マッチする拡張子を持つモノを一時変数へ格納して返す。
NSArray *extensions = @[@"jpg", @"png", @"tiff"];
NSArray *files = @[@"a.word", @"b.tiff", @"c.xls", @"d.png", @"e.txt", ];
NSLog(@"with the extensions: %@", [files pathsMatchingExtensions:extensions] );

NSMutableArray

初期化

NSMutableArray *aMutableArray1 = [NSMutableArray arrayWithCapacity:10];
NSMutableArray *aMutableArray2 = [NSMutableArray array]; // 空の配列

[ aMutableArray1 setArray:@[@"6.plist", @"使えない.word", @"1.tiff", @"2.xls", ]];

NSMutableArray *aMutalbeArray3 = @[@"234", @"34567"].mutableCopy;

追加、置換、削除

追加

[aMutableArray addObject:@"末尾へ追加"];
[aMutableArray addObjectsFromArray: otherArray];
[aMutableArray insertObject:@"挿入" atIndex:2]; // インデックスは、0から始まる。

置換

[aMutableArray replaceObjectAtIndex:2 withObject:@"置換した要素"];
 // replaceWithRange 範囲の要素を削除して、代わりに引数の配列で置き換える。
NSArray *aReplacements = @[@"部分", @"置換"];
NSRange aRange = NSMakeRange(0, aReplacement.count);
[aMutableArray replaceObjectsInRange:aRange withObjectsFromArray:aReplacements];
// 丸ごと置換
[aMutableArray setArray:otherArray];
//要素の交換
[aMutableArray exchangeObjectAtIndex:5 withObjectAtIndex:2];

削除

//末尾の要素を削除
[aMutableArray removeLastObject];
//引数インデックスにある要素を削除
[aMutableArray removeObjectAtIndex:2];
//NSRange を使用して、範囲にある要素を削除
NSRange aRange = NSMakeRange(2, 2);
[aMutableArray removeObjectsInRange:aRange];
//引数オブジェクトと同じ要素を全て削除
// 等しいとは、isEqualTo で比較して、YESを返すもの。
// アドレスが同じなら等しい。
[aMutableArray removeObject:@"6.plist"];
//引数配列の中にある要素1つと一致で、削除
[aMutableArray removeObjectsInArray:@[@"1.tiff", @"4.txt"]];

NSMutableArrayの要素を調べて、条件が成り立つ要素を削除

ループで実装。要素を最後から調べること、でないと循環してしまう。
NSInteger len, idx;
len = aMutableArray.count;
BOOL check1 = NO;
for (idx = len - 1 ; idx >= 0 ; idx-- ) {
	NSString *aStr = [aMutableArray objectAtIndex:idx];
	check1 = [aStr doesContainNumber];
	if ( check1 ) {
		[aMutableArray removeObjectAtIndex:idx];
	}
}

ソート。NSArray と違い、自分が持つ要素をソートする。

セレクタを用いたソート

[aMutableArray sortUsingSelector:@selector(compare:)];

カテゴリで追加した、自前のソートセレクタでソート

//NSString をソートする簡単なメソッドをカテゴリで追加
@interface NSString (categoryExtension)
- (NSComparisonResult) myCompare:(NSString *) counterString;
- (BOOL) doesContainNumber;
@end
@implementation NSString (categoryExtension)
- (NSComparisonResult) myCompare:(NSString *)counterString {
	NSString *leftString = self;
	NSString *rightString = counterString;
	NSUInteger lengthOfLeftString = leftString.length;
	NSUInteger lengthOfRightString = rightString.length;
	if ( lengthOfLeftString < lengthOfRightString) {
		return NSOrderedAscending;
	} else if ( lengthOfLeftString > lengthOfRightString ) {
		return NSOrderedDescending;
	} else {
		// same length
		// compare each character step by step
		for (int i = 0 ; i <= lengthOfRightString; i++ ) {
			unichar leftChar = [leftString characterAtIndex:i];
			unichar rightChar = [rightString characterAtIndex:i];
			if (leftChar < rightChar ) {
				return NSOrderedAscending;
			} else if ( leftChar > rightChar ) {
				return NSOrderedDescending;
			} // if ends
		} // for ends
	} // if ends
	return NSOrderedSame;
}
@end
[aMutableArray sortUsingSelector:@selector(myCompare:)];

ブロックを用いたソート

[aMutableArray sortUsingComparator
	:^(NSString *leftStr, NSString *rightStr)
	{
		NSUInteger leftLength = leftStr.length;
		NSUInteger rightLength = rightStr.length;
		if (leftLength < rightLength) {
			return NSOrderedDescending;
		} else if (leftLength > rightLength ) {
			return NSOrderedAscending;
		} else {
			for (int i = 0 ; i <= leftLength ; i++ ) {
				unichar leftChar = [leftStr characterAtIndex:i];
				unichar rightChar = [rightStr characterAtIndex:i];
				if (leftChar < rightChar ) {
					return NSOrderedDescending;
				} else if ( leftChar > rightChar ) {
					return NSOrderedAscending;
				}
			}
		}
		return NSOrderedSame;
	}
];

関数を用いたソート

//美しくない。色んなところで利用するなら、あり。
// 関数ポインターの定義
NSComparisonResult (*pointerFunction)(__strong id, __strong id, void *);
pointerFunction = compareFunction;
void *aContext = NULL; // 関数への第三引数、任意。これを使って比較動作を細かく設定できる、
[aMutableArray sortUsingFunction:pointerFunction context:aContext];

列挙

高速列挙

for (id anObject in anArray) {
	NSLog(@"%@", [anObject description]);
}

逆順の高速列挙

for ( id anObject in [aArray reverseObjectEnumerator] ) {
	NSLog(@"%@", [anObject description]);
}

列挙子を使う

id anObject;
NSEnumerator *anEnumerator;
anEnumerator = [aArray objectEnumerator];
while ( (anObject = [anEnumerator nextObject]) != nil) {
	NSLog(@"enumerator: %@", [anObject description] );
}

列挙子の逆順

anEnumerator = [anArray reverseObjectEnumerator];
for (anObject in anEnumerator ) { /* 省略 */ }