Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/115.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在不点击主线程的情况下保存NSManagedObjectContext_Ios_Objective C_Multithreading_Swift_Magicalrecord - Fatal编程技术网

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执行后台同步。我正在使用,但它并不是特别针对它
  • 确保我正确地使用了上下文&例如
我真正的问题是:我的理解正确吗?最后还有几个问题

因此,MagicalRecord提供的上下文是:

  • PrivateQueueConcurrencyType的MR_rootSavingContext,用于将数据持久化到存储,这是一个缓慢的过程
  • MainQueueConcurrencyType的MR_defaultContext
  • 对于后台,您需要使用由MR_context()生成的上下文,该上下文是MR_defaultContext的子级,属于PrivateQueueConcurrencyType
现在,为了以异步方式保存,我们有两个选项:

  • MR_saveToPersistentStoreWithCompletion()它将一直保存到MR_rootSavingContext并写入磁盘
  • MR_saveOnlySelfWithCompletion()它最多只能保存到父上下文(即,对于使用MR_上下文创建的上下文,MR_defaultContext)
从那时起,我认为我可以在不冻结UI的情况下执行以下操作(我们称之为尝试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
但是,我的假设是错误的。我只保存了自己的完成,并看到它依赖于

[self performBlock:saveBlock];
哪个

在接收方队列上异步执行给定的块

所以我有点困惑,因为我希望它不会因此而阻塞UI

然后我尝试了(我们称之为尝试2)

这很管用,但感觉不对

然后我在箱子里发现了一些东西

将消息发送到使用队列创建的上下文时 关联时,必须使用performBlock:或performBlockAndWait: 方法,如果您的代码尚未在该队列上执行(对于 主队列类型)或在performBlock的范围内。。。调用 (对于专用队列类型)。在传递给那些 方法,您可以自由使用NSManagedObjectContext的方法

因此,我假设:

  • 尝试#1冻结UI,因为我实际上是从主队列调用它,而不是在performBlock的范围内
  • 尝试#2可以工作,但我正在创建另一个线程,而上下文已经有了自己的背景线程
所以我应该使用saveWithBlock:

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完成
它仍然不明白的是如何使用MR_save[…]with completion()。我会在MR_上下文中使用它,但是因为它在我的测试用例中阻塞了主线程,所以我看不到它何时变得相关(或者我错过了什么…)


谢谢你的时间:)

好的,我很少使用魔法记录,但因为你说你的问题更一般,我会尝试回答

一些理论:当创建一个上下文时,你会传递一个指示器,指示你是想把它绑定到主线程还是后台线程

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完成

现在,在尝试1中

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)