谨慎在遍历数组时删除元素

我们想要删除数组中的符合条件的元素时,经常对数组进行遍历,然后删除。但是这其中更确隐藏着很大的问题。如果当初能够仔细的分析一下,也不会导致今天的错误了。

比如我们有一个数组 CCArray *array;包含了value值分别为1~5的NSNumber对象,现在我们想删除其中value为1和2的两个对象,我们可能会这样操作:

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.    }

但这样操作,只会删除value为1的对象。因为删除这个对象后,array的count减少了,被删掉的对象后面的元素会向前移动,这样在这个for循环中就会漏掉1后面的那个对象,而且测试也发现,虽然循环中间删除了一个元素,但循环的次数并没有减少,只不过最后两次都是最后一个元素。

打印的值如下:

l  number:0

l  number:1

l  delete:1

l  number:3

l  number:4

l  number:4

如果我们使用如下的循环方式:

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]);

}

}

打印的值会变为:

l  Number 0:0

l  Number 1:1

l  delete:1

l  number 2:3

l  number 3:4

可见同样的问题,在删除value为1的对象后,计数器增长为2,但此时数组中下标为2的元素已经变成了之前下标为3的对象,因为删除其中一个元素后,后面的所有元素都会向前移动,这个下标都会改变。这样变漏掉了一些元素。对于for in快速枚举,还会多次执行最后一个元素的遍历,这些都是导致问题的隐患。

为了避免以上的问题,我们可以使用倒序的方式删除:

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]);

}

}

另外也可以通过创建临时数组的方式来解决,将所有要保留的对象加入另外一个数组,并完全删除原数组,或者将要删除的元素加入临时数组,然后执行[CCArray removeObjectInArray:];

你可能感兴趣的:(谨慎在遍历数组时删除元素)