我們想要?jiǎng)h除數(shù)組中的符合條件的元素時(shí),經(jīng)常對(duì)數(shù)組進(jìn)行遍歷,然后刪除。但是這其中更確隱藏著很大的問(wèn)題。如果當(dāng)初能夠仔細(xì)的分析一下,也不會(huì)導(dǎo)致今天的錯(cuò)誤了。
比如我們有一個(gè)數(shù)組 CCArray *array;包含了value值分別為1~5的NSNumber對(duì)象,現(xiàn)在我們想刪除其中value為1和2的兩個(gè)對(duì)象,我們可能會(huì)這樣操作:
1.? for(NSNumber * number in array)
2.? {
3.? ? ? ? ? CCLOG(@"number:%@ ",[number description]);
4.? ? ? ? ? if([number intValue]==2||[number intValue]==1) {
5.? ? ? ? ? ? ? [array removeObject:number];
6.? ? ? ? ? ? ? CCLOG(@"delete:%@ ",[number description]);
7.? ? ? ? ? }
8.? ? }
但這樣操作,只會(huì)刪除value為1的對(duì)象。因?yàn)閯h除這個(gè)對(duì)象后,array的count減少了,被刪掉的對(duì)象后面的元素會(huì)向前移動(dòng),這樣在這個(gè)for循環(huán)中就會(huì)漏掉1后面的那個(gè)對(duì)象,而且測(cè)試也發(fā)現(xiàn),雖然循環(huán)中間刪除了一個(gè)元素,但循環(huán)的次數(shù)并沒(méi)有減少,只不過(guò)最后兩次都是最后一個(gè)元素。
打印的值如下:
l? number:0
l? number:1
l? delete:1
l? number:3
l? number:4
l? number:4
如果我們使用如下的循環(huán)方式:
for (int i=0;i<[array count];i++) {
NSNumber *number = [array objectAtIndex:i];
CCLOG(@"number %d:%@ ",i,[number description]);
if ([number intValue]==2||[number intValue]==1) {
[array removeObject:number];
CCLOG(@"delete:%@ ",[number description]);
}
}
打印的值會(huì)變?yōu)椋?/p>
l? Number 0:0
l? Number 1:1
l? delete:1
l? number 2:3
l? number 3:4
可見同樣的問(wèn)題,在刪除value為1的對(duì)象后,計(jì)數(shù)器增長(zhǎng)為2,但此時(shí)數(shù)組中下標(biāo)為2的元素已經(jīng)變成了之前下標(biāo)為3的對(duì)象,因?yàn)閯h除其中一個(gè)元素后,后面的所有元素都會(huì)向前移動(dòng),這個(gè)下標(biāo)都會(huì)改變。這樣變漏掉了一些元素。對(duì)于for in快速枚舉,還會(huì)多次執(zhí)行最后一個(gè)元素的遍歷,這些都是導(dǎo)致問(wèn)題的隱患。
為了避免以上的問(wèn)題,我們可以使用倒序的方式刪除:
int num = [array count];
for (int i=num-1;i>=0;i--) {
NSNumber *number = [array objectAtIndex:i];
CCLOG(@"number %d:%@ ",i,[number description]);
if ([number intValue]==2||[number intValue]==1) {
[array removeObjectAtIndex:i];
CCLOG(@"delete:%@ ",[number description]);
}
}
另外也可以通過(guò)創(chuàng)建臨時(shí)數(shù)組的方式來(lái)解決,將所有要保留的對(duì)象加入另外一個(gè)數(shù)組,并完全刪除原數(shù)組,或者將要?jiǎng)h除的元素加入臨時(shí)數(shù)組,然后執(zhí)行[CCArray removeObjectInArray:];