swift2 罕见的核心数据崩溃“nilOutReservedCurrentEventSnapshot”

j0pj023g  于 2022-11-23  发布在  Swift
关注(0)|答案(3)|浏览(202)

我的应用程序中发生了一次崩溃,这种情况很少发生(可能每运行30次就发生一次)。错误代码包含一个奇怪的选择器名称_nilOutReservedCurrentEventSnapshot__,我根本找不到任何相关文档。以下是我的控制台提供的信息:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType _nilOutReservedCurrentEventSnapshot__]: unrecognized selector sent to instance 0x157b51e0'
*** First throw call stack:
(0x2358810b 0x22d2ee17 0x2358d925 0x2358b559 0x234bbc08 0x24cbf445 0x24ca4d99 0x249bec 0x245c90 0x19b68c 0x24a5c97 0x24b05ab 0x24a8ef9 0x24b1a8d 0x24b18e7 0x232bfb29 0x232bf718)
libc++abi.dylib: terminating with uncaught exception of type NSException

如果有人能解释一下_nilOutReservedCurrentEventSnapshot__'这个短语的含义,那将对我有很大帮助。下面是崩溃位置的截图:

nfeuvbwi

nfeuvbwi1#

不幸的是,你在网上找不到多少关于_nilOutReservedCurrentEventSnapshot__的信息。
它可能与托管对象的快照生命周期相关。
当Core Data从持久性存储中提取对象时,它会获取其状态的快照。快照是对象持久性属性的字典-通常是对象的所有属性以及与之具有一对一关系的任何对象的全局ID。快照参与乐观锁定。当框架保存时,它将每个已编辑对象的快照中的值与持久性存储器中的当前对应值进行比较。
_nilOutReservedCurrentEventSnapshot__未被记录的事实意味着这种类型的行为不应该发生。

我们所知道的是它是NSManagedObject类的函数。

因此,错误unrecognized selector sent to instance的原因是_nilOutReservedCurrentEventSnapshot__被调用到一个不是NSManagedObject的对象上,因为NSManagedObject被释放了,其他的东西现在填充了它的内存。这是事实。
关于应用的性质及其CoreData设置的问题没有给出上下文,但可以推断它正在使用父子并发模式。这一点很重要。

[图像检索自here]

从我所能找到的有关堆栈溢出的所有问题来看,它们似乎都使用了父子并发模式。

此问题完全可能是由于采用此模式时未正确实现或处理ManagedObjects而导致的。
可以使用父子上下文的情况是当同步云数据或处理当用户使用放弃或撤消所做的更改的选项来编辑某些内容时所做的更改时,这可以在后台线程上完成。
问题中还提到,这种情况很少发生,不会每次都发生。这意味着,在进行某个保存或更改之前,上下文可能很好,但不知何故,上下文变得不同步,执行另一次保存会导致应用崩溃。
从文档中的“在上下文之间同步更改”:
如果您在应用程序中使用多个受管对象上下文,Core Data不会自动通知一个上下文对另一个上下文中的对象所做的更改。通常,这是因为上下文是一个暂存区,您可以在其中单独更改对象,并且可以放弃更改而不影响其他上下文。
保存子项时,更改将发送到父项上下文,但如果单独更改父项,则不会发送到父项上下文。强烈建议您 * 切勿 * 更改父项上下文;仅通过保存子上下文并从那里传播更改。
崩溃的可能原因

有几个因素可能会导致此问题,但有两个因素比较突出:

1.从引用中释放ManagedObject,该引用由于解除iOS应用程序中的模态视图或OSX应用程序中的工作表而被释放。

可能解决方案:提取ManagedObjects之前,请将子上下文的retainsRegisteredObjects属性设置为true(然后在保存上下文后将其设置为false,以避免进一步的潜在内存泄漏)。警告!
例如ctx.retainsRegisteredObjects = true

2.未处理的上下文更改。

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/ChangeManagement.html#//apple_ref/doc/uid/TP40001075-CH22-SW1
假设一个应用程序有两个受管对象上下文和一个持久存储协调器。(moc 1),则可能需要通知第二个上下文(moc 2)对象已被删除。在所有情况下,moc 1通过NSNotificationCenter自动发布NSManagedObjectContextDidSaveNotification通知,您的应用程序应注册该通知并将其用作任何它需要采取的动作。此通知不仅包含已删除对象的相关信息,也包含已变更对象的相关信息。您需要行程这些变更,因为它们可能是删除的结果。这些类型的变更中,大部分都涉及暂时性关系或撷取的属性。
可能的解决方案如下:

  • 在上下文中使用块方法。refer to callback function at bottom of linked file.
  • 在上下文之间传递ManagedObjects时,请确保使用objectWithID
  • 使用NSManagedObjectContextDidSaveNotification触发器对对象更改采取适当的操作。
  • 正在删除对ManagedObject的所有强引用。可能是对在给定代码的作用域之外使用的ManagedObject进行了强引用,因此当父级取消分配ManagedObject而子级没有取消分配时,在将来保存时,子级对该ManagedObject执行了另一次保存,然后父上下文尝试保存已取消分配的ManagedObject。"it is a good pattern to try to fetch objects, modify them, save them and reset the edit [child] context"
    因为这里没有其他信息来推断导致错误的原因,并且我无法重现它。我建议尝试使用Instruments中的Zombie分析来查找您的ManagedObject被释放的位置。

如果随后向其中一个已取消分配的对象(现在是NSCombie对象)发送消息,则会标记该僵停对象,应用会崩溃,录制停止,并显示"僵停消息"对话框。然后,您可以检查僵停对象的保留和释放历史记录,以确定问题发生的确切位置。
https://github.com/iascchen/SwiftCoreDataSimpleDemo/blob/master/SwiftCoreDataSimpleDemo/CoreDataHelper.swift
希望有人能更清楚地说明是什么导致了这个问题。
+++++++++++++++++++++++++++++++++

    • 附注:**

父/子上下文可能会导致UI-“every fetch request and every save operation will fully block the main thread while data is read or written to/from disk”.出现停顿,这是因为每次获取都是通过父上下文(在主线程上)拉到子上下文的。
支持SO应答
如果您正在使用这种方法,建议您重新考虑设计,例如 * 将两个独立的托管对象上下文连接到同一个持久存储协调器*这样可以"避免"将来发生这种问题。


[从here检索到的图像]
您可以看到linked articlelinked article之间的巨大性能差异。

zfciruhq

zfciruhq2#

_nilOutReservedCurrentEventSnapshot__NSManagedObject上的私有方法,用于在内部刷新Core Data对象的属性和值。您可以在NSManagedObjecthere的私有标头中看到它。
__NSCFType是Objective-C运行时内部使用的Core Foundation类型的私有 Package 器。您可以通过查看私有头文件here了解更多信息,但没有太多内容可看。
如果没有完整的回溯,就很难调试特定的问题。在我看来,可能有两个原因:
1.上下文的parentObject因某种原因无效。
1.您正尝试将Core Foundation对象另存为NSManagedObject上的属性,但该对象并不需要该属性。

sgtfey8w

sgtfey8w3#

大胆猜测..是否有机会从创建上下文的实际线程之外的其他线程调用此保存方法?为了安全起见,请始终执行Save:从执行/ PerformBlockAndWait执行操作。

相关问题