objective-c - 我该如何解决 "Collection was mutated while being enumerated"、 @synrchonized 、 mutableCopy 或其他问题?

标签 objective-c multithreading grand-central-dispatch synchronized

在 Crashlytics 中,我发现我的用户很少遇到崩溃。有问题的代码看起来像这样......

- (void)updateIsAnsweredField:(NSArray *)moduleItemsList
{
    if (moduleItemsList && self.answeredItems && self.answeredItems.count > 0) {
        for (ModuleItem * item in moduleItemsList) { // "Collection was mutated while being enumerated"
            if ([item isKindOfClass:[ModuleItem class]] && [item shouldCheckIfAnswered]) {
                item.answered = [self isAnsweredItem:item.moduleID];
            }
        }
    }
}

Crashlytics给出的错误可以在上面代码片段的注释中看到。

我认为有几种方法可以解决这个问题。

1) 将函数内的所有内容包装在 @synchronized(moduleItemsList) {} 中。这是解决问题的理想方法吗?我听说 @synchronized 非常慢,因此应尽可能避免使用它。

2) 创建一个副本 NSMutableArray *copyModuleItemsList = [moduleItemsList mutableCopy]; 。然后一一列举。这能解决问题吗?我认为它会解决这个特定问题,但还会有另一个问题不是吗?那是......最后当我们将我们的副本分配回原来的a la moduleItemsList = copyModuleItemsList;时, moduleItemsList 可能同时在不同的线程上发生了变化。

3) 跟踪传入的:(NSArray *)moduleItemsList任何人将其作为属性(property)持有。然后覆盖getter以使用dispatch_sync,并覆盖setter以使用dispatch_barrier_async。但是,不能保证原始数组是任何其 getter 和 setter 可以被覆盖的类的属性。实际上,这一切都没有意义,因为我们不会专门更改该数组,不是吗?

我有点困惑。有人可以协助解决这个问题吗? #1 是我想要的选项吗?

编辑:添加更多代码

[item shouldCheckIFAnswered] :

这只是检查 ModuleItem 类中存在的 @property 值。 if self.moduleType == ModuleTypeSuchAndSuch

isAnsweredItem: :

- (BOOL)isAnsweredItem:(NSString *)moduleID
{
    if (!self.answeredItems) {
        return NO;
    }

    return [self.answeredItems containsObject:moduleID];
}

最佳答案

从您的帖子来看,听起来 moduleItemsList 正在另一个线程中被修改。解决此问题的“正确”方法将取决于另一个线程中的状态与此线程中的状态之间所需的关系。

如果您在此代码中以及在另一个线程中修改集合的代码中使用 @synchronized(moduleItemsList) ,那么当此代码运行时,它'将始终拥有 moduleItemsList 的“最新” View 。

如果将 moduleItemsList 复制到另一个对象中,则当此代码运行时,它可能会在不再位于 moduleItemsList 中的项目上设置 answered,或者可能无法在最近添加到 moduleItemsList 的项目上设置 answered 标志。

一般来说,@synchronized 版本是获得“正确”行为的更简单方法。仅当您确定两个线程对 moduleItemsList 的当前内容可能存在分歧并不重要时,您才需要使用 copy。

I've heard @synchronized is very slow and to avoid it when possible.

总的来说,这是一个糟糕的建议。 @synchronized 的速度与确保线程之间状态一致并提供可重入锁所需的速度一样慢。不管你愿意与否,你都不想在所有事情上都使用 @synchronized ,但它是同步线程之间数据访问的一个很好的解决方案 - 毕竟这就是它的用途。 .

关于objective-c - 我该如何解决 "Collection was mutated while being enumerated"、 @synrchonized 、 mutableCopy 或其他问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35584021/

相关文章:

iphone - 刷新过程应在后台运行,但是子处理需要同步

multithreading - 单独线程中的无限循环

c - Pthread_t 未启动

c - 等待所有线程计时器回调完成的安全方法

ios - 为什么必须在主队列上异步调用 resignFirstResponder() 来关闭键盘

iphone - 用户启用安全登录时的 facebook 安全警告 - iPhone

ios - 使用键盘滑动 UIScrollView 并向上移动 View

IOS/objective-C : UIActivityViewController: Customize for different Activity Types

ios - 类似于 Facebook/Google 搜索引擎的索引搜索

ios - 在 HTTP 方法中使用 POST 请求保存 UI?