【问题标题】:Understanding Xcode crash message and @synchronized directive了解 Xcode 崩溃消息和 @synchronized 指令
【发布时间】:2023-03-24 02:45:01
【问题描述】:

尝试编写一些代码,使用 iCloudKit 单例以及全局变量单例来跨多个方法调用共享变量和进程,可能来自多个 iPad。我有两个问题。

代码现在因这条消息而崩溃。

2015-06-09 18:31:18.879 iBeacons Demo[277:24157] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSDictionaryM: 0x17024fdb0> was mutated while being enumerated.'

*** First throw call stack:

(0x184a742d8 0x1960340e4 0x184a73c8c 0x100024b0c 0x185975f9c 0x184a2c240 0x184a2b4e4 0x184a29594 0x1849552d4 0x18e0336fc 0x18951afac 0x10005eacc 0x1966b2a08)

libc++abi.dylib: terminating with uncaught exception of type NSException

据我了解,这是通过两种方法尝试更改可变字典对象的共享实例中的值。对 OOC 有点陌生,对多线程环境和 xCode 中的编程同样陌生,我有一个愚蠢的问题。

如何在此处追踪 0x17024fdb0 所指的 NSMutableDictionary 对象?

假设我发现它可以/将潜在的解决方法是使其属性声明像这样是原子的,同时使用 @synchronized 指令。

所以我有...

property (retain, atomic) NSDictionary blah 

还有

@synchronized(self) {
  // do something quickly
}

【问题讨论】:

  • 这个问题的一个更典型的根源是您正在迭代一个数组(for 循环或enumerateObjectsWithBlock 或类似的东西)并尝试添加或删除对象,同时仍然遍历数组。这可能发生在最简单的单线程代码中,并且与与多线程代码同步无关。如果您正在编写多线程代码,则无论如何都应该同步数组,但这不是问题的最可能根源。 (顺便说一句,这里不需要atomic,只需@synchronized 或其他一些同步机制。)
  • 谢谢罗布;你是对的,我在通过它的同时从可变 NSDictionary 中删除了一个对象,尽管我仍然怀疑它必须执行多线程。会勾选你的答案......但你能告诉我我如何找到它在显示参考时崩溃的有问题的 NSDictionary,我怎样才能更容易地在 Xcode 中找到它?
  • @user3069232 打开 Xcode 左侧窗格中的“断点”选项卡,按底部的 +,选择“添加异常断点”。然后,当您下次在附加调试器的情况下运行并引发异常时,它将跳转到创建异常的行并允许您查询当前程序状态。一个通常在语义上正确的快速解决方法是将for (x in dictionary) 切换为for (x in [dictionary allKeys]),因为allKeys 被声明为copy 属性——所以你从开始迭代时开始迭代键的副本,而不是现场演出。

标签: ios xcode multithreading atomic synchronized


【解决方案1】:

特雷斯邦,

你说得对,尽管公平地说,汤米的回答是引导我解决问题的人。

for (NSString *student in studentNClass) {
if ([descriptions containsObject:student] ) {
    [studentNClass removeObjectForKey:student];
} else {
    [self addBeacon2Carousel:student];
    //singleBeaconsFound++;
    self.beaconsFound.text = [NSString stringWithFormat:@"%d",singleBeaconsFound];;
}

在汤米之后..

for (NSString *student in [studentNClass allKeys]) {
    if ([descriptions containsObject:student] ) {
            [studentNClass removeObjectForKey:student];
    } else {
        [self addBeacon2Carousel:student];
        //singleBeaconsFound++;
        self.beaconsFound.text = [NSString stringWithFormat:@"%d",singleBeaconsFound];;
    }
}

谢谢!

【讨论】:

  • Tommy/Rob 也想以某种方式在背面进行堆栈交换,但是如果我没有通过单击星号答案来解决这个迷宫般的界面,那么它也太新了!
【解决方案2】:

此问题的典型根源在于您正在遍历数组(例如 for 循环或 enumerateObjectsWithBlock 或类似的东西)并尝试添加或删除对象,同时仍在遍历数组。这可能发生在最简单的单线程代码中,并且与同步多线程代码无关。

显然,如果您正在编写多线程代码,则无论如何也应该同步数组,但这可能不是这里的问题。这个问题很可能只是改变了数组,同时仍然在 for 循环中遍历数组。


在您的回答中,您建议您删除所有键值在另一个数组中的字典键/值对。您当然可以使用 Tommy 建议的 allKeys 模式。或者,在这种情况下,使用removeObjectsForKeys 可能更容易:

[students removeObjectsForKeys:descriptions];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多