Ios 在不点击主线程的情况下保存NSManagedObjectContext
我想做的是:Ios 在不点击主线程的情况下保存NSManagedObjectContext,ios,objective-c,multithreading,swift,magicalrecord,Ios,Objective C,Multithreading,Swift,Magicalrecord,我想做的是: 在不冻结UI的情况下,使用web API执行后台同步。我正在使用,但它并不是特别针对它 确保我正确地使用了上下文&例如 我真正的问题是:我的理解正确吗?最后还有几个问题 因此,MagicalRecord提供的上下文是: PrivateQueueConcurrencyType的MR_rootSavingContext,用于将数据持久化到存储,这是一个缓慢的过程 MainQueueConcurrencyType的MR_defaultContext 对于后台,您需要使用由MR_co
- 在不冻结UI的情况下,使用web API执行后台同步。我正在使用,但它并不是特别针对它
- 确保我正确地使用了上下文&例如
- PrivateQueueConcurrencyType的MR_rootSavingContext,用于将数据持久化到存储,这是一个缓慢的过程
- MainQueueConcurrencyType的MR_defaultContext
- 对于后台,您需要使用由MR_context()生成的上下文,该上下文是MR_defaultContext的子级,属于PrivateQueueConcurrencyType
- MR_saveToPersistentStoreWithCompletion()它将一直保存到MR_rootSavingContext并写入磁盘
- MR_saveOnlySelfWithCompletion()它最多只能保存到父上下文(即,对于使用MR_上下文创建的上下文,MR_defaultContext)
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
但是,我的假设是错误的。我只保存了自己的完成,并看到它依赖于
[self performBlock:saveBlock];
哪个
在接收方队列上异步执行给定的块
所以我有点困惑,因为我希望它不会因此而阻塞UI
然后我尝试了(我们称之为尝试2)
这很管用,但感觉不对
然后我在箱子里发现了一些东西
将消息发送到使用队列创建的上下文时
关联时,必须使用performBlock:或performBlockAndWait:
方法,如果您的代码尚未在该队列上执行(对于
主队列类型)或在performBlock的范围内。。。调用
(对于专用队列类型)。在传递给那些
方法,您可以自由使用NSManagedObjectContext的方法
因此,我假设:
- 尝试#1冻结UI,因为我实际上是从主队列调用它,而不是在performBlock的范围内
- 尝试#2可以工作,但我正在创建另一个线程,而上下文已经有了自己的背景线程
MagicalRecord.saveWithBlock { (localContext) -> Void in
for i in 1...1_000 {
User.MR_createInContext(context)
}
}
这将执行PrivateQueueConcurrencyType的操作。
多亏了,所有涉及到MR_rootSavingContext的更改都将提供给MR_defaultContext
看来:
- MR_defaultContext是显示数据的最佳上下文
- 最好在MR_上下文(MR_defaultContext的子上下文)中进行编辑
- 长时间运行的任务(如服务器同步)最好使用saveWithBlock完成
谢谢你的时间:)好的,我很少使用魔法记录,但因为你说你的问题更一般,我会尝试回答 一些理论:当创建一个上下文时,你会传递一个指示器,指示你是想把它绑定到主线程还是后台线程
let context = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
“绑定”是指线程在内部被上下文引用。在上面的示例中,上下文创建并拥有一个新线程。此线程不会自动使用,但必须显式调用,如下所示:
context.performBlock({ () -> Void in
context.save(nil)
return
});
因此,使用“dispatch_async”的代码是错误的,因为上下文绑定到的线程只能从上下文本身引用(它是一个私有线程)
从上面可以推断,如果上下文绑定到主线程,那么从主线程调用performBlock将不会执行与直接调用上下文方法不同的操作
要在结尾评论您的要点,请执行以下操作:
- MR_defaultContext是显示数据的最佳上下文:必须从它所在的上下文访问NSManagedObject 创建,因此实际上只有上下文可以为 用户界面从
- 最好在MR_上下文(MR_defaultContext的子上下文)中进行编辑:编辑成本不高,您应该遵循 上面的规则。如果您正在调用从主线程编辑NSManagedObject属性的函数(如点击按钮) 您应该更新主上下文。另一方面,节省是必要的 这就是为什么您的主上下文不应该链接到 直接持久化存储,但只需将其编辑下推到根目录 具有拥有持久存储的后台并发的上下文
- 长时间运行的任务(如服务器同步)最好使用saveWithBlock Yes完成
for i in 1...1_000 {
let user = User.MR_createInContext(context) as User
}
context.MR_saveOnlySelfWithCompletion(nil)
无需为每次对象创建进行保存。即使UI没有被阻塞,这也是浪费
关于吴先生。在魔法记录的文档中,我看不到“MR_上下文”,所以我想知道它是否是访问主上下文的快速方法。如果是这样,它将阻塞。谢谢,有趣的答案。“没有必要为每个对象创建都保存。”-事实上,我这样做是为了确保主线程上的任何阻塞都很容易被发现,我应该提到这一点。MR_saveOnlySelfWithCompletion在内部调用performBlock,这就是为什么我不理解UI被阻止的原因。performBlock不保证它将在后台线程上执行,但在上下文绑定的线程上执行。如果这是主上下文,它将正常阻止。基本上,在主线程上调用上下文方法时
for i in 1...1_000 {
let user = User.MR_createInContext(context) as User
}
context.MR_saveOnlySelfWithCompletion(nil)