我正在通过后台线程拥有的新创建的 NSManagedObjectContext 在后台线程(使用 GCD)上执行昂贵的获取(约 5 秒,大约 30,000 个对象)。
但是,我没有在后台执行此操作的好处,因为主线程正在等待持久存储上的锁定,因此 UI 被冻结。这是堆栈跟踪:
* thread #1: tid = 0x1c03, 0x3641be78 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) lockObjectStore], stop reason = breakpoint 1.1
frame #0: 0x3641be78 CoreData`-[NSManagedObjectContext(_NSInternalAdditions) lockObjectStore]
frame #1: 0x36432f06 CoreData`-[_PFManagedObjectReferenceQueue _processReferenceQueue:] + 1754
frame #2: 0x36435fd6 CoreData`_performRunLoopAction + 202
frame #3: 0x35ab9b1a CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 18
frame #4: 0x35ab7d56 CoreFoundation`__CFRunLoopDoObservers + 258
frame #5: 0x35ab80b0 CoreFoundation`__CFRunLoopRun + 760
frame #6: 0x35a3b4a4 CoreFoundation`CFRunLoopRunSpecific + 300
frame #7: 0x35a3b36c CoreFoundation`CFRunLoopRunInMode + 104
frame #8: 0x376d7438 GraphicsServices`GSEventRunModal + 136
frame #9: 0x33547cd4 UIKit`UIApplicationMain + 1080
frame #10: 0x000f337a MyApp`main + 90 at main.m:16
我(相信)我已经确认当这个后台线程正在工作时我没有访问主线程的 NSManagedObjectContext 。从堆栈跟踪来看,很明显我没有直接对 Core Data 做任何事情。但是某些事情触发了对 _processReferenceQueue: 的调用,这导致尝试锁定存储。有谁碰巧知道这个方法的作用以及我如何/如果我可以防止它在我的后台线程正在工作时被调用?
编辑
在我开始这个后台获取之后,我没有在主线程上进行任何核心数据读取或写入。这就是为什么这很令人费解。如果主线程也试图做更多的工作,我希望会有争执,但事实并非如此——至少,我没有要求它这样做。没有读取,没有写入,没有 FRC。这就是为什么我想知道是否有人熟悉这个 _processReferenceQueue 方法。为什么会被调用?我能做什么导致它运行?
编辑
作为一个测试,我试图让 MT 的 MOC 进入一个状态,在我关闭 BT 进行提取之前,它没有待处理的更改,希望它不需要做任何_processReferenceQueue
需要锁的工作在商店里。
在开始 BT 之前,我注意到[MOC updatedObjects]
集合中有一个对象。插入或删除集中没有对象。
调用后[MOC save]
,[MOC updatedObjects]
集合是空的,正如预期的那样。
然而,一旦我启动了 BT,MT 仍然试图将商店锁定在里面_processReferenceQueue
,即使MOC 中应该没有任何东西是脏的。
我尝试的下一件事(严格作为测试)是MOC reset]
在启动 BT 之前调用 [。同样,[MOC updatedObjects]
正如预期的那样,重置后集合是空的。在代码中的这一点上,在 BT 完成其工作之前,我不会接触 MT 上的任何托管对象(因此,由于重置使我已经引用的托管对象无效,我不会遇到任何问题)。然而,这一次,MT 没有尝试将持久存储锁定在_processReferenceQueue
.
这种行为向我表明,在我启动 BT 之后,我没有对 MT 上的 MOC 做任何明确的事情。否则,MT 会在_processReferenceQueue
. 但它没有。
我不确定为什么最近保存的 MOC 需要随后锁定,_processReferenceQueue
而最近重置的 MOC 不需要。
我会继续挖掘。
谢谢!布赖恩