NSMutableArrayでつまずいた2つのこと


昨日NSMutableArrayを使っていて2カ所でつまずいたのでメモ。

高速列挙子でアクセス中の配列の要素を追加、削除しないこと!


for(NSString * str in ary){
	if([str isEqualToString:targetStr]){
		[ary removeObject:str];
	}
}

このようにFast Enumerationを使ってアクセスしているときに配列の要素を追加、削除すると

Collection was mutated while being enumerated

のエラーになる。


for(NSString * str in [ary reverseObjectEnumerator]){
	if([str isEqualToString:targetStr]){
		[ary removeObject:str];
	}
}

のようにして配列の最後から最初に向かって読み込むようにすると問題は解決する。
何番目の要素を操作するかを記録しておいて、forループの外で操作するようにしたりしてもいいかも。

参考
【コラム】ダイナミックObjective-C (105) Fast Enumeration(1) – 速い列挙子 | 開発・SE | マイナビニュース
Objective-Cと戦うブログ: 高速列挙でエラー「Collection was mutated while being enumerated.」が出た

NSUserDefaultsからmutableArrayを読み込むときはmutableCopyすること


NSMutableArray * ary = [[NSUserDefaults standardUserDefaults] objectForKey:aryKey];
[ary addObject:@"d"];

このようにすると以下のエラーになる。

'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'

「変更できないオブジェクトに、変更しようとするメソッドが送られたよ」と。
userdefaultsからNSMutableArrayを読み込むときは、immutableな配列が返ってくるので以下のようにmutableCopyしてやる必要があるらしい。


NSMutableArray * ary = [[[NSUserDefaults standardUserDefaults] objectForKey:aryKey] mutableCopy];
[ary addObject:@"d"];

マニュアルのobjectForKey:の項目を読むと、確かにimmutableになると書いてある。

Special Considerations
The returned object is immutable, even if the value you originally set was mutable.

が、参考になる記事が見つからなかったら結構悩んだに違いない。
先人に感謝。

参考
きみが思い出になる前に - NSUserDefaultsに保存したmutableなオブジェクトはmutableCopyを使って作り直す

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です