0

我有一个我不断迭代NSMutableArrayUIImageViews(使用 a CADisplayLink)。我这样做是为了UIImageViews在屏幕上不断移动。

当我UIImageView从数组中删除 a 时,有时会出现错误:

EXC_BAD_ACCESS (code=1, address=0x20000008)

但是,在我开始使用 ARC/iOS6 之前,我过去常常收到错误“数组在被枚举时发生变异”,所以我认为这两个错误的含义完全相同,但我不确定。

无论如何,这是我的问题。使用以下任何方法从数组中删除 aUIImageView会给我上述错误。

[imageViews removeObject:imageView];

[imageViews performSelector:@selector(removeObject:) withObject:imageView];

[imageViews performSelectorOnMainThread:@selector(removeObject:) withObject:imageView waitUntilDone:YES];

但是,使用以下任何一种方法都不会给我错误。

[imageViews performSelectorOnMainThread:@selector(removeObject:) withObject:imageView waitUntilDone:NO];

[imageViews performSelector:@selector(removeObject:) withObject:imageView afterDelay:.01];

那么有人可以向我解释为什么从NSMutableArray使用上面列出的第一组方法中删除一个对象会给我我认为“数组在被枚举时发生突变”的错误,而使用第二组方法永远不会给我这个错误?

我一直在使用上面列出的第二组方法来解决这个错误(如果我使用它们,一切都很好)但我想知道为什么我的问题在我使用它们时得到了解决,以及它是否安全使用这两种方法之一。

这是我第一次发布问题,如果我以错误的方式发布此问题,请原谅我。

4

2 回答 2

2

因为 CADisplayLink 在后台线程上回调,所以完全有可能通过调度有问题的数组从所述线程中删除给定对象,另一个正在变异或枚举数组的过程中,这会引发异常。前两种方法不起作用,因为它们需要对数组进行同步访问(NSMutableArray 不提供),并且它们调度在当前线程的运行循环中,而不是主线程,因此不能保证它们各自的执行不能同时访问同一个资源。底部的两个工作是因为,假设您在主线程上改变数组,该运行循环不可能安排指令枚举和指令同时突变(一个线程不能在同时,特别是当该代码被安排在运行循环的下一次迭代中时),因此该数组的访问更加安全。通过使用延迟,您创建了一个竞争条件,这对您来说到目前为止已经奏效,但稍后会再次困扰您。

于 2013-03-11T22:35:27.190 回答
1

当您枚举一个数组时(使用 for ... in ... 循环遍历它或使用 NSEnumerator),枚举要求您在循环本身或同时在另一个线程上根本不更改数组(因此原始警告)。

我不知道为什么底部的两种方法有效 - 我会在内部猜测它们以不影响枚举的方式更改数组。

话虽如此,这是不好的做法,我不建议在枚举期间以任何方式更改数组。即使今天有效,明天也可能无效。我建议将要删除的索引存储到枚举之后,然后按照此答案删除它们。

于 2013-03-11T22:02:25.663 回答