奔溃日志:was mutated while being enumerated
这两天发现app的一个崩溃,提示是
*** Collection <CALayerArray: 0x18904630> was mutated while being enumerated.
找了一天终于找到了罪魁祸首,代码是这样的
for (NSInteger i = 0; i < postArr.count; i++) {
for (NSInteger j = i+1; j < postArr.count; j++) {
MoviePhoto *mp = postArr[i];
MoviePhoto *secMp =postArr[j];
if ([mp.photoUrl.value isEqualToString:secMp.photoUrl.value]) {
[postArr removeObject:mp];//删除重复对象
}
}
}
原因是这样的,for循环在编译的时候可能就不会改变被遍历数组的数据,当进入if语句数组进行remove了之后,再去遍历数组,发现被遍历数组和编译的时候不一样。此时就会造成崩溃。
在使用数组的时候,我们应该避免遍历数组时不要对数组进行操作。但是对于我们有时候要使用到对用一个数组进行遍历又要进行修改的时候,网上提供了两种方法:
NSMutableArray
* arrayTemp = xxx;
NSArray
* array = [
NSArray
arrayWithArray: arrayTemp];
for
(
NSDictionary
* dic in array) {
if
(condition){
[arrayTemp removeObject:dic];
}
}
NSMutableArray
*tempArray = [[
NSMutableArray
alloc]initWithObjects:
@"12"
,
@"23"
,
@"34"
,
@"45"
,
@"56"
,
nil
];
[tempArray enumerateObjectsUsingBlock:^(
id
obj,
NSUInteger
idx,
BOOL
*stop) {
if
([obj isEqualToString:
@"34"
]) {
*stop =
YES
;
if
(*stop ==
YES
) {
[tempArray replaceObjectAtIndex:idx withObject:
@"3333333"
];
}
}
if
(*stop) {
NSLog
(
@"array is %@"
,tempArray);
}
}];
PS:利用block来操作,根据查阅资料,发现block便利比for便利快20%左右;
如果都不是数组遍历的原因,有可能是线程的原因。这里贴上了网上的一些资料:
因为我们在下载时, 使用了Block每当接受到数据,就去更新一下一个UIScrollView中的下载进度条的百分比。
而另有一个NSTimer, 会隔一段时间把这个UIScrollView中的全部元素清空,然后再重新添加, 因为可能有动态的元素需要添加或者删除。
运行时, 就会出现,两个线程同时去访问的情况, 当Block正在去更新UIScrollView中的这个元素时, NSTimer中可能正在执行清除操作,所以就崩了。
原来,在同一时间,不同的线程同时读取和修改了NSMutaleArray。
解决办法:避免多线程同时去修改一个对象, 避免做遍历时,这个对象被修改,根据这个思想,可以考虑加锁,或者直接使用atomic的方式来做。