【问题标题】:Why Core Data concurrency debug tool crashes my iOS app?为什么 Core Data 并发调试工具会导致我的 iOS 应用程序崩溃?
【发布时间】:2020-10-01 20:30:57
【问题描述】:

我怀疑最近有人遇到过这样奇怪的问题。

当使用"-com.apple.CoreData.ConcurrencyDebug 1" 时,在运行参数中,如果其名称(PRODUCT_NAME 构建设置)以“音乐”开头,iOS 是 14.0 或 14.01(目前是最新版本),Xcode 会持续崩溃 iOS 应用程序,并执行一些基本的、完全有效的并发核心数据 API。 只需将 PRODUCT_NAME 更改为其他内容(例如,从“音乐收藏”更改为“我的音乐收藏)”即可防止崩溃。因此,通过简单地在两个选项之间切换应用程序名称,然后运行调试器,人们应该清楚地注意到应用程序崩溃而不是相应地崩溃。这应该是应用名称影响功能的明确证据。

我检测到这个问题是因为我的应用在 App Store 上可用,以“音乐”开头,并且在可以重现的特定条件下崩溃。更改我的应用名称时,相同的可重现场景不会导致崩溃。我花了将近一周的时间才找到这个问题,因为我不认为应用名称可能是根本原因。

通过在 Xcode 12 中创建一个新项目并添加几行代码,可以轻松重现 "-com.apple.CoreData.ConcurrencyDebug 1" 在执行有效代码时导致应用程序崩溃(但应用程序名称以“音乐”开头)的问题。以下链接中的说明如下所示。

我向 Apple 反馈助理提交了一份报告: https://feedbackassistant.apple.com/feedback/8761671

我还在 Apple 开发者论坛上详细描述了这个问题: https://developer.apple.com/forums/thread/662602

很高兴得到任何反馈。

【问题讨论】:

  • 这真的很奇怪!我注意到如果 moc 是使用 NSMainQueueConcurrencyType 构建的,则没有错误。
  • 没错。它只会发生在后台线程 (NSPrivateQueueConcurrencyType) 中。

标签: ios xcode core-data concurrency ios14


【解决方案1】:

我得到相同的结果。这看起来像是一个内部问题,可能会影响至少一些以与 Apple 的 iOS 应用相同的字母开头的其他应用名称。

这里有一个可能会有所帮助的解决方法。查看断言发生时的完整堆栈跟踪:

* thread #2, queue = 'com.apple.root.user-initiated-qos', stop reason = EXC_BREAKPOINT (code=1, subcode=0x184e68d68)
  * frame #0: 0x0000000184e68d68 CoreData`+[NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__] + 12
    frame #1: 0x0000000184e68c4c CoreData`_PFAssertSafeMultiThreadedAccess_impl + 548
    frame #2: 0x0000000184e68a24 CoreData`__68-[NSManagedObjectContext _PFAutoreleasePoolReferenceQueueTrampoline]_block_invoke + 92
    frame #3: 0x0000000184e32b2c CoreData`-[_PFAutoreleasePoolThunk dealloc] + 40
    frame #4: 0x00000001801858e8 libobjc.A.dylib`AutoreleasePoolPage::releaseUntil(objc_object**) + 204
    frame #5: 0x00000001801857b8 libobjc.A.dylib`objc_autoreleasePoolPop + 236
    frame #6: 0x00000001024f8fac libdispatch.dylib`_dispatch_last_resort_autorelease_pool_pop + 40
    frame #7: 0x000000010250b37c libdispatch.dylib`_dispatch_root_queue_drain + 1428
    frame #8: 0x000000010250b928 libdispatch.dylib`_dispatch_worker_thread2 + 136
    frame #9: 0x00000001bad2175c libsystem_pthread.dylib`_pthread_wqthread + 212

请注意,靠近堆中间的帧提到了自动释放。这暗示了一个行动方案,因为如果您可以影响框架中自动发布的方式,您可能会改变行为。事实上,如果您将@autoreleasepool 添加到您的performBlockAndWait

    [managedObjectContext performBlockAndWait:^{
        @autoreleasepool {
            NSError *error = nil;
            NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"TestEnt"];
            NSArray *result = [managedObjectContext executeFetchRequest:request error:&error];
            NSLog(@"result=%@", result);
        }
    }];

...违规行为消失。我不知道这对您的真实代码和演示代码是否有帮助,但可能值得一试。

顺便说一句,找到这确实是一项出色的侦探工作。干得好。

【讨论】:

  • 作为另一个数据点.... 在试验 OP 的示例时,我将 managedObjectContext 设为实例变量以避免自动释放逻辑,并直接在 executeFetchRequest 上遇到相同的崩溃。
  • 汤姆,出色的工作。不幸的是,我无法应用它,因为我使用的是 3rd 方库。我希望尽快得到 Apple 的回复。
  • @Joshua 闭源?很抱歉听到它。也许在您使用该库时的一些技巧会有所帮助。
  • 不,它是开源的,但有数百个 performBlockAndWait 调用。也许我现在应该更改我的应用名称?
  • 似乎要么就是这样,要么求助于方法调配来修补框架。
猜你喜欢
  • 2021-12-27
  • 1970-01-01
  • 2011-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-16
相关资源
最近更新 更多