核心数据:父上下文阻止子级

Tho*_*mer 5 multithreading core-data nsmanagedobjectcontext ios

我正在使用核心数据在应用程序中进行一些后台处理.后台处理在子managedObjectContext上完成.上下文初始化

appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

// the moc in appDelegate is created with .MainQueueConcurrencyType
mainThreadMOC = appDelegate.managedObjectContext!
backgroundMOC = NSManagedObjectContext(concurrencyType:NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
backgroundMOC?.parentContext = mainThreadMOC
Run Code Online (Sandbox Code Playgroud)

后台处理按以下方法完成:

// download all new transaction log entries
func syncItems() {

... set up the query object for parse

let moc = CoreDataStore.sharedInstance.backgroundMOC

// perform download
moc?.performBlock( {
    self.runQuery(query)   // Download stuff und do some core data work
    })
}
Run Code Online (Sandbox Code Playgroud)

调试器显示块内的所有工作确实在后台线程中.

当我从主线程调用此函数并立即使用冗长的核心数据操作阻止主线程(用于测试目的)时,我看到后台线程停止并且仅在主线程空闲时继续执行.

// this is called from a view controller in the main thread

syncItems() // should start to work in background
for i in 0...200 {
    // do some core data work in main thread
}
// syncItems starts to work after the blocking for-loop ends.
Run Code Online (Sandbox Code Playgroud)

为什么会这样?

Dan*_*ert 17

不要使用父子上下文设置.

对于任何事情来说,亲子语境都不是一个好方法.只需使用一个简单的堆栈:两个上下文与一个共享持久存储协调器.

亲子语境只会增加很多混乱,而不会给你太多任何东西.这是一个相当误解的概念.我希望像mzarra这样的人会停止提倡这种设置.这对社区是一种伤害.

如果你的背景情境是你的主要背景的孩子而言,你不得不锁定两个主体和背景情况下,每当背景方面需要保存.这会阻止UI.并且您必须第二次锁定UI以将这些更改从UI传播到PSC.如果使用后台上下文,则必须将更改合并到主上下文中,但您只能为当前在该上下文中注册的对象执行操作.如果添加了新对象,或者当前未注册(引用)的更新/删除对象,那么基本上是无操作.

  • 一个上下文使用`MainQueueConcurrencyType`,一个使用`PrivateQueueConcurrencyType`.您可以通过监听did-save-notifications并将它们与`mergeChangesFromContextDidSaveNotification()`合并来合并更改.这描述了许多地方,包括出书:https://www.objc.io/books/core-data/ (4认同)

Tim*_*ers 0

当您在评论中说“一些核心数据在主线程中工作”时,该工作是在访问吗mainThreadMOC

听起来也许主线程工作正在锁定runQuery需要访问的东西。

尝试将阻塞主线程的测试繁忙工作更改为不访问核心数据(NSThread.sleepForTimeInterval应该这样做)的内容,然后看看是否可以让后台runQuery工作。

如果这是问题所在,您需要将主线程工作重构为不会阻止runQuery.