【问题标题】:NSArrayM was mutated while being enumerated - adding objects, not removingNSArrayM 在枚举时发生了变异 - 添加对象,而不是删除
【发布时间】:2017-08-28 19:57:03
【问题描述】:

我尝试在 StackOverflow 上查看所有这些问题,但找不到任何对我有帮助的东西。我什至不能自己复制它,我是通过 iTunes Connect 从实际用户那里得到的。这是 Xcode 上的崩溃日志:

这是我的完整 serializedLocations 方法正在崩溃,没有任何内容被剥离:

- (NSMutableArray *)serializedLocations:(NSArray *)locations withTimestamp:(NSInteger)timestamp{
    NSMutableArray *serializedLocations = [NSMutableArray new];

    if(locations){
        for (CLLocation *location in locations) {
            NSInteger locationTimeInterval = floor([location.timestamp timeIntervalSince1970] * 1000);
            NSInteger t = locationTimeInterval - timestamp;
            NSMutableDictionary *serializedLocation = [NSMutableDictionary new];
            serializedLocation[@"x"] = [NSNumber numberWithDouble:location.coordinate.latitude];
            serializedLocation[@"y"] = [NSNumber numberWithDouble:location.coordinate.longitude];
            serializedLocation[@"a"] = [NSNumber numberWithDouble:location.horizontalAccuracy];
            serializedLocation[@"v"] = [NSNumber numberWithDouble:location.speed];
            serializedLocation[@"o"] = [NSNumber numberWithDouble:location.course];
            serializedLocation[@"t"] = [NSNumber numberWithLong:t];
            [serializedLocations addObject:serializedLocation];
        }
    }
    return serializedLocations;
}

我似乎找不到缺陷。

  • 我正在创建一个临时新数组。
  • 我没有更改我正在枚举的数组。
  • 我正在向临时数组添加新对象。
  • 我正在返回那个新的临时数组

编辑:

让所有其他方法运行的父级是这样调用的:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [ApiClient insertEvent:event withLocations:locations];
    });

【问题讨论】:

  • 但它发生在后台线程上?如果locations 本身是可变的怎么办?如果在后台线程持有对它的引用时它被其他东西变异了怎么办?我没有看到你在这里做任何事情来使这段代码线程安全。
  • 是的,它发生在后台线程上。愿意分享我如何使这段代码成为线程安全的吗?
  • 我应该只创建位置的副本并枚举该副本吗?
  • “分享”是整个问题。你想要做的是分享locations。最起码,为什么不先做一个深拷贝呢? — 哦,我看到了,当我打字的时候,你想到了! :)
  • :D 谢谢@matt,我现在就自己做。如果您想做出正确的答案,我很乐意选择它。谢谢!

标签: ios objective-c arrays


【解决方案1】:

我猜locations,虽然在这里键入为一个 NSArray,但实际上是一个 NSMutableArray — 而 this 是在您枚举它时正在改变的数组。如果您要在后台线程上运行此代码,则需要确保 locations 没有在“背后”发生变异。一种简单的方法是在调用站点制作locations 的深层副本并传递 that 而不是可变数组。 (请注意,在serializedLocations:withTimestamp: 中进行深层复制是不够的,因为locations 可能在复制过程中发生变异。)

【讨论】:

  • 哦,我正要这样做。没有意识到它可以在“复制期间”发生变异。我知道这不是这个问题的主题,但是有没有办法实际测试这个?
  • 我们在这里谈论的是多线程!假设一件事不可能发生真的是个坏主意。总是假设最坏的情况。毕竟,不这样做就是你陷入困境的原因;您正在跨线程肆意共享一个可变对象。这从一开始就是糟糕的设计。你很幸运,问题以如此清晰的形式出现,甚至可以猜测原因。更常见的是,线程问题比实际错误晚得多。我建议您立即返回所有代码并寻找其他多线程的地方。
猜你喜欢
  • 2012-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-08
  • 2017-11-22
  • 2015-02-01
  • 2014-02-15
  • 1970-01-01
相关资源
最近更新 更多