遇到一个闪退,在开发的时候,遇到过,但是很难复现,但是偶尔还是会有出现的,就是这样一个问题
NSArrayM: 0xb550c30> was mutated while being enumerated
这段报错,看起来是一个正在遍历一个数组的时候,我们修改了它导致的,但是我们的代码中并没有在一个for 循环中或者 enumerate中去改变一个数组的操作,后来推测,
有可能是一个数组在被遍历的时候,被其他线程修改了,导致的这个问题。
后来排查代码,确实是这个问题,
下面贴出代码,方便大家借鉴
获取数据的方法
- (NSDictionary *)getMergedDataWithKeys:(NSArray *)keys {
NSMutableDictionary *getData = [[NSMutableDictionary alloc] init];
for (NSString *key in keys) {
for (NSDictionary *tosynchronizedData in self.DataList) {
NSString *tosynchronizedIDString = [tosynchronizedData objectForKey:@"id"];
if (![key isEqualToString:tosynchronizedIDString]) continue;
[getData addEntriesFromDictionary:[tosynchronizedData objectForKey:@"data"]];
break;
}
}
return getSynchronizedData;
}
崩溃就是崩溃在上面这段循环遍历的代码中了
但是问题出在我们其他的放的调用上,
更新数据的方法
- (void)updateDic:(NSArray *)newData {
NSMutableArray *keysToUpdate = [[NSMutableArray alloc] init];
for (NSDictionary *data in newData) {
NSString *IDString = [data stringForKey:@"id"];
NSString *type = [data stringForKey:@"type" "];
NSDictionary *tmpData = [data dictionaryForKey:@"data"];
if (IDString.length <= 0 || type.length <= 0 || tmpData.count <= 0) continue;
NSUInteger synchronizedTemplateDataToUpdateIndex = 0;
NSDictionary *synchronizedTemplateDataToUpdate = nil;
for (NSUInteger i = 0; i < self.synchronizedDataList.count; i++) {
NSDictionary *synchronizedData = [self.synchronizedDataList objectOrNilAtIndex:i];
NSString *synchronizedIDString = [synchronizedData stringForKey_ap:@"id" defaultValue:@""];
NSString *synchronizedType = [synchronizedData stringForKey_ap:@"type" defaultValue:@""];
NSMutableDictionary *synchronizedTemplateData = [[synchronizedData dictionaryForKey_ap:@"data"] mutableCopy];
if (![synchronizedIDString isEqualToString:IDString] || ![synchronizedType isEqualToString:type]) continue;
for (NSString *key in tmpData.allKeys) {
NSString *value = [tmpData stringForKey:key];
[synchronizedTemplateData setObject:value forKey:key];
}
synchronizedTmpDataToUpdateIndex = i;
synchronizedTmpDataToUpdate = @{
@"id": IDString,
@"type": type,
@"data": synchronizedTemplateData
};
break;
}
if (synchronizedTemplateDataToUpdate == nil) {
[self.DataList addObject:data];
} else {
[self.DataList removeObjectAtIndex:synchronizedTemplateDataToUpdateIndex];
[self.DataList addObject:synchronizedTemplateDataToUpdate];
}
[keysToUpdate addObjectOrNil:@{
@"id": IDString ?: @"",
@"type": type ?: @""
}];
}
}
调用的地方,
其他地方都是主线程在掉用,获取也是在主线程,
但是新写了一个调用修改数据的地方,在自线程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
updateDic
});
修复
dispatch_async(dispatch_get_main_queue(), ^{
updateDic
});