NSFetchedResultsController 委托和后台驱动的更新
我在开发访客管理应用程序时遇到了 NSFetchedResultsController 问题。
该应用程序基本上在后台下载来宾列表(使用 NSOperation 子类),将它们插入到托管对象上下文中,然后将它们呈现在 UI 线程上的表视图中。
我认为我遵循核心数据多线程规则(我有单独的 MOC 用于在其线程上创建的操作,我使用保存通知等同步我的主 MOC)。
我不完全理解的是 NSFetchedResultsController 的行为,它似乎在后台线程而不是主线程调用其委托方法(controllerDidChangeContent 等),这会导致非法的 UI 更新。
所以我的问题是 - 使用 NSFetchedResultsControllerDelegate 观察来自 MOC 保存通知的更改是否合法,还是 NSFetchedResultsControllerDelegate 设计为仅适用于主线程上完成的更改?
我不确定我的解释是否足够清楚,如果不是我可以发布一些代码来演示问题。
I ran into NSFetchedResultsController issue developing guest-management application.
The application basically downloads list of guests on background (using NSOperation subclass), inserts them to managed object context and then presents them in table view on UI thread.
I think that I am following the core data multi-threading rules (I have separate MOC for the operation created on its thread, I synchronize my main MOC using did-save notification etc.).
What I do not fully understand is the behavior of NSFetchedResultsController which seems to be calling its delegate methods (controllerDidChangeContent etc.) at background thread instead of main thread which leads to illegal UI updates.
So my question is - is it legal to use NSFetchedResultsControllerDelegate to observe changes that come from MOC did save notification or is NSFetchedResultsControllerDelegate designed to work only with changes done on the main thread?
I'm not sure if my explanation is clear enough, if not I can post some code to demonstrate the problem.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我的猜测是,您的 MOC 保存通知是在后台线程而不是主事件线程上发送和观察的。这将导致 NSFetchedResultsControllerDelegate 在后台线程上发送委托消息。
您需要确保您的保存通知观察者将控制权传递给主线程,例如:
My guess is that your MOC did-save notification is being sent and observed on the background thread instead of the main event thread. This would cause the
NSFetchedResultsControllerDelegate
to send delegate messages on the background thread.You need to make sure your did-save notification observer passes control to the main thread, e.g:
免责声明
Daniel Dickison 回复是正确答案。我在这里仅提供一些额外的细节和解释,因为其中一些步骤并不简单。
使用 2 个不同的托管对象上下文是正确的做法
UI 线程 MOC:
传输、下载、后台 MOC:
使用后台 MOC 进行后台操作:
(比如新数据被下载并保存)
将Daniel Dickison'响应应用于后台托管对象上下文,根据 Apple 文档:
注意:我通常更喜欢使用
performBlockAndWait()
和waitUntilDone: true
除非我确信不等待不会导致竞争条件。如果您决定不等待,我邀请您对您的应用程序进行彻底的压力测试。我冒昧地让后台线程等待 UI,但从不相反。从 UI 线程监听
NSFetchedResultsController
必须使用MainQueueConcurrencyType
托管对象上下文。您的
NSFetchedResultsController
从后台托管对象上下文中释放,并将接收controllerWillChangeContent
、didChangeObject
等。之后合并已完成。Disclaimer
Daniel Dickison response is the right answer. I'm only offering here some extra details and explanations, since some of these steps are not trivial.
Using 2 distinct Managed Object Contexts is the right thing to do
UI Thread MOC:
Transport, Download, Background MOC:
Use the background MOC for background operations:
(Such as new data was downloaded and saved)
Apply Daniel Dickison' response to the background Managed Object Context, in accordance to the Apple documentation:
Note: I generally prefer to use
performBlockAndWait()
andwaitUntilDone: true
unless I positively know that not waiting will not cause race conditions. I invite you to thoroughly stress test your application if you decide to not wait. I take the liberty to have the background thread wait for the UI, but never the other way around.Listen from the UI thread
NSFetchedResultsController
must useMainQueueConcurrencyType
Managed Object Context.Your
NSFetchedResultsController
is freed from the background Managed Object Context, and will receivecontrollerWillChangeContent
,didChangeObject
, etc. after the merge has been completed.