我想要做的事情:
- 使用Web API进行后台同步而不冻结用户界面。我正在使用MagicalRecord,但它并不是特别针对此项任务。
- 确保我正确地使用了上下文等内容
我的真正问题是:我的理解正确吗?最后还有几个问题。
因此,MagicalRecord提供的上下文包括:
- MR_rootSavingContext,类型为PrivateQueueConcurrencyType,用于将数据保存到存储中,这是一个缓慢的过程
- MR_defaultContext,类型为MainQueueConcurrencyType
- 对于后台操作,您需要使用由MR_context()生成的上下文,它是MR_defaultContext的子级,类型为PrivateQueueConcurrencyType
现在,对于异步保存,我们有两个选项:
- MR_saveToPersistentStoreWithCompletion():将保存所有到MR_rootSavingContext的内容并写入磁盘。
- MR_saveOnlySelfWithCompletion():仅保存到父级上下文(即使用MR_context创建的上下文的MR_defaultContext)。
从那里开始,我认为我可以尝试以下操作(我们称之为Attempt#1),而不会冻结用户界面:
let context = NSManagedObjectContext.MR_context()
for i in 1...1_000 {
let user = User.MR_createInContext(context) as User
context.MR_saveOnlySelfWithCompletion(nil)
}
// I would normally call MR_saveOnlySelfWithCompletion here, but calling it inside the loop makes any UI block easier to spot
但是,我的假设是错误的。我查看了一下 MR_saveOnlySelfWithCompletion,并发现它依赖于
[self performBlock:saveBlock];
根据苹果文档,此方法在接收者队列上异步执行给定的块。
在接收者队列上异步执行给定的块。
所以我有点困惑,因为我期望它不会阻塞UI。
然后我尝试了(让我们称其为Attempt#2)
let context = NSManagedObjectContext.MR_context()
for i in 1...1_000 {
let user = User.MR_createInContext(context) as User
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -> Void in
context.MR_saveOnlySelfWithCompletion(nil)
}
}
这个方法可以完成任务,但感觉不太正确。
然后我在iOS 5.0的发布说明中发现了一些内容
当向与队列关联的上下文发送消息时,如果您的代码没有在该队列上执行(对于主队列类型)或者在performBlock... 调用范围内(对于私有队列类型),则必须使用performBlock: 或 performBlockAndWait: 方法。在传递给这些方法的块中,您可以自由地使用NSManagedObjectContext 的方法。
所以,我认为:
- 尝试#1会冻结UI,因为我实际上是从主队列调用它,而不是在performBlock的范围内
- 尝试#2虽然有效,但在上下文已经有自己的后台线程的情况下,我又创建了另一个线程
所以当然我应该使用saveWithBlock:
MagicalRecord.saveWithBlock { (localContext) -> Void in
for i in 1...1_000 {
User.MR_createInContext(context)
}
}
这执行操作在MR_rootSavingContext的直接子级上,其类型为PrivateQueueConcurrencyType。由于rootContextChanged,任何传递到MR_rootSavingContext的更改都将对MR_defaultContext可用。
因此,似乎:
- MR_defaultContext是显示数据的完美上下文 - 最好使用MR_context(MR_defaultContext的子级)进行编辑 - 最好使用saveWithBlock执行长时间运行的任务,例如服务器同步
我仍然不明白如何使用MR_save[…]WithCompletion()。 我会在MR_context上使用它,但由于在我的测试用例中它阻塞了主线程,所以我不知道它何时变得相关(或者我错过了什么...)。
感谢您的时间 :)