【转】was mutated while being enumerated 你是不是以为你真的懂For...in... ??

原文网址:http://www.jianshu.com/p/ad80d9443a92

支持原创,如需转载, 请注明出处
你是不是以为你真的懂For...in... ??
哈哈哈哈, 我也碰到了这个报错 .
究其原因, 顾名思义 "在枚举的时候发生了变化"
for...in...利用了快速枚举NSFastEnumerate
当我们想要改变数组变量中的数据或者删除数组中的数据的时候,不能用for...in...

应该是Objective-C中的foreach循环与Java中的相似,在内部是用iterator(迭代器)实现遍历的。而不管是在Java还是C++中,一旦修改了被遍历对象,在修改前生成的iterator都会失效,所以《C++ Primer》及Java课本中曾警告过不要在用iterator遍历集合时增删集合元素,看来Objective-C中也是一样。
NSArray的枚举操作中有一条需要注意:对于可变数组进行枚举操作时,你不能通过添加或删除对象这类操作来改变数组容器。如果你这么做了,枚举器会很困惑,而你将得到未定义的结果。

所以我这里给出三种解决方案
1.利用for loop ()

       for (int i = 0; i < arr.count; i++) {
            if (...) {
                // do sth ;
            }
        }

2.利用临时变量

   NSArray *tmp = [NSArray arrayWithArray:arr];
        for (id obj in tmp) {
            if (...) {
               // do sth ;
            }
        }

3.enumerateObjectsUsingBlock(推荐)

    [arr enumerateObjectsUsingBlock:^(NSMutableDictionary *obj, NSUInteger idx, BOOL *stop) {
            if (...) {
                // do sth
                *stop = YES; // 相当于break ; stop控制跳出枚举器.
            }
        }];

2条评论 ( 按时间正序· 按时间倒序· 按喜欢排序添加新评论

闭上眼睛

2 楼 · 2016.04.14 11:53

第二种方法,利用变量, 你的意思是遍历的是 tmp 操作的是 arr 对吧.我有个疑问就是在操作完 arr 之后赋值给 tmp 这个不会造成 was mutated while being enumerate 这个错误么?

喜欢(0) 回复

爱吃草莓的Rock

3 楼 · 2016.04.26 13:04

楼主,建议你应该写详细点,方法二补充下:
NSMutableArray *duplicateArray = [OriginalArray mutableCopy];
for(id obj in duplicateArray){
    if ([ob isEqualToString:@"3"]){
      [OriginalArray removeObject:obj];
    }
  }

*** First throw call stack:

(0x353d088f 0x37777259 0x353d03b3 0x34e576a9 0x34ea914d 0x1252d9 0x16c281 0x16aadb 0x3425f887 0x3425f281 0x3425f911 0x16a931 0x3425dc59 0x34260817 0x3278ddfb 0x3278dcd0)

terminate called throwing an exception

 

*** First throw call stack:

(0x353d088f 0x37777259 0x353d03b3 0x34e576a9 0x34ea914d 0x1252d9 0x16c281 0x16aadb 0x3425f887 0x3425f281 0x3425f911 0x16a931 0x3425dc59 0x34260817 0x3278ddfb 0x3278dcd0)

terminate called throwing an exception2013-04-08 15:03:06.800 NanGuangTV[45122:707] *** Terminating app due to uncaught exception ‘NSGenericException‘, reason: ‘*** Collection <__NSArrayM: 0x8ef350> was mutated while being enumerated.‘

*** First throw call stack:

(0x353d088f 0x37777259 0x353d03b3 0x34e576a9 0x34ea914d 0x1252d9 0x16c281 0x16aadb 0x3425f887 0x3425f281 0x3425f911 0x16a931 0x3425dc59 0x34260817 0x3278ddfb 0x3278dcd0)

terminate called throwing an exception(lldb) 

 

遇到这么个问题。郁闷。

原来是,我用了多线程,分别读取一个NSMutaleArray时报出来的Error!

原来,在同一时间,不同的线程同时读取和修改了NSMutaleArray。

遇到一个问题,跟踪了半天才发现原因。(现象是,客户老是说在下载的过程中,过一会就出现崩溃的现象, 只要点了下载按钮, 不做任何操作, 然后期刊就开始正常下载了,过大概5分钟后,再去看,程序就已经崩溃了)

在做《时装传媒》ipad应用时,首页的下载页面,下载时,会不断地去更新页面上的下载进度,同时还有一个15秒的timer, 会每15秒切换当前显示的是男装,女装或者艺术刊页面。这个timer会把当前的scrollView中显示的封面图片进行移除,然后再替换,以实现自动更换首页封面的功能

 

崩溃时提示:

Collection <UIButtonContent: 0x2341234> was mutated while being enumerated

(在网上搜了一下,发现有一个类似的问题:‘NSGenericException‘, reason: ‘*** Collection <__NSArrayM: 0x8ef350> was mutated while being enumerated.‘)

根据这个提示, 想了一下,觉得应该在做遍历的过程中,修改了这个NSArray或者是NSMutableArray。后来想想, 这可能是多线程并发访问时出现的问题, 沿崩溃时的堆栈找了一下,果然找到。

因为我们在下载时, 使用了Block每当接受到数据,就去更新一下一个UIScrollView中的下载进度条的百分比。

而另有一个NSTimer, 会隔一段时间把这个UIScrollView中的全部元素清空,然后再重新添加, 因为可能有动态的元素需要添加或者删除。

运行时, 就会出现,两个线程同时去访问的情况, 当Block正在去更新UIScrollView中的这个元素时, NSTimer中可能正在执行清除操作,所以就崩了。

原来,在同一时间,不同的线程同时读取和修改了NSMutaleArray。

解决办法:避免多线程同时去修改一个对象, 避免做遍历时,这个对象被修改,根据这个思想,可以考虑加锁,或者直接使用atomic的方式来做。

时间: 2024-10-06 22:54:47

【转】was mutated while being enumerated 你是不是以为你真的懂For...in... ??的相关文章

奔溃日志: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];

异常Crash之 NSGenericException,NSArray was mutated while being enumerated

*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x17542520> was mutated while being enumerated.' 从字面上不难理解,Crash的原因在于我们一边遍历数组,一边修改该数组数据.例如:      NSMutableArray *OriginalArray = [NSMutableArray

解决Collection &lt;__NSArrayM: 0xb550c30&gt; was mutated while being enumerated

当程序出现这个提示的时候,是因为你一边便利数组,又同时修改这个数组里面的内容,导致崩溃,网上的方法如下: 1 2 3 4 5 6 7 8 9 NSMutableArray * arrayTemp = xxx; NSArray * array = [NSArray arrayWithArray: arrayTemp]; for (NSDictionary * dic in array) {    if (condition){       [arrayTemp removeObject:dic];

【学习ios之路:Object-C错误】Collection &lt;__NSArrayM: 0xb550c30&gt; was mutated while being enumerated.

错误提示: 产生错误的原因: 当程序在执行遍历时,同时又修改数组中的内容,导致崩溃. 解决方法如下: 方法1:定义一个一模一样的数组,遍历新数组的同时,对原数组进行操作修改. 例如: NSMutableArray *arrayTemp = [@[@"aa",@"vv",@"bb"] mutableCopy]; NSArray *array = [NSArray arrayWithArray: arrayTemp]; for (NSString *

Bug-iOS: Collection &lt;__NSArrayM: 0x&gt; was mutated while being enumerated.

//init a NSArray NSMutableArray *arr2 = [NSMutableArray array]; for (int i=0; i<10; ++i) { NSMutableDictionary *d = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%d", i], @"a", nil]; [arr2 addObject:

Objective-C学习篇07—NSArray与NSMutableArray

大纲 NSArray NSMutableArray 快速枚举 NSArray NSArray是一个静态数组,也就是一个不可变数组,一旦创建以后,就不能进行添加,删除或者修改其中的元素.NSArray继承自NSObject,用于管理一系列有序对象的集合,可以通过对象在数组中的位置(索引)来访问对象.和C语言一样,数组中元素的索引是从0开始的.数组中既可以用于存放同一个类的对象,也可以用于存储不同类的对象.但不能存放nil,nil被视为数组结束的标志,系统会在方法末尾自动生成. 切记:NSArray

Objective-C 高性能的循环遍历 forin - NSEnumerator - 枚举 优化

Cocoa编程的一个通常的任务是要去循环遍历一个对象的集合  (例如,一个 NSArray, NSSet 或者是 NSDictionary). 这个看似简单的问题有广泛数量的解决方案,它们中的许多不乏有对性能方面问题的细微考虑. 对于速度的追求 首先,是一个免责声明: 相比其它问题而言,一个 Objective-C 方法原始的速度是你在编程时最后才需要考虑的问题之一 – 区别就在于这个问题够不上去同其它更加需要重点考虑的问题进行比较,比如说代码的清晰度和可读性. 但速度的次要性并不妨碍我们去理解

直播项目详解

项目下载地址 项目文件结构: Login : 登录页面集成了友盟第三方登录微信和QQ,新浪授权登录是请求新浪官方的OAuth请求,以及一些登录所需要的资源 Main :主要包含标签视图控制器UITabBarController .导航控制器UINavigationController.数据请求工具类XLLiveTool.业务逻辑类XLDealData.代理类.pch文件和单例的头文件,都是一些全局都能用的东西. Home : 首页,主要包括热门,最新和关注三部分,把这三部分添加到(XLHomeV

iOS for 和 forin 的区别 以及注意事项

一 效率: for VS for(... in ...) for 的应用范围广基本可以NSArray.NSArray以及C语言的数组等,而for(... in ...)仅限于NSArray.NSArray等 for(... in ...) 更简洁.效率更高 测试代码: 10^7 的数组,时间单位 秒,精确度 毫秒 NSMutableArray *test = [NSMutableArray array]; for (int i= 0; i < 10000000; i++) { [test add