Ton*_*Lin 3 multithreading core-data thread-safety ios swift
在我的程序中,它使用两者
DispatchQueue.global(qos: .background)
Run Code Online (Sandbox Code Playgroud)
和
self.concurrentQueue.sync(flags: .barrier)
Run Code Online (Sandbox Code Playgroud)
处理后台多线程问题.
它是迅速3所以我使用最新的方式来获取childContext:
lazy var context: NSManagedObjectContext = {
return (UIApplication.shared.delegate as! AppDelegate).persistentContainer.newBackgroundContext()
}()
Run Code Online (Sandbox Code Playgroud)
我也启用-com.apple.CoreData.ConcurrencyDebug 1了调试
然后出现问题:
1,当有API调用并且在回调块(后台线程)中时,我需要获取核心数据,编辑,然后保存.我尝试使用上面代码中的self.context来调用performBlockAndWait并执行save此块内部.整个过程很顺利但是当我尝试在此块之外但在回调块内部访问我的结果时,会发生错误.我也尝试getObjectById通过self.context和self.context.parent 获取objectId,并且此行发生错误.我做错了什么,我应该怎么做?因为我需要在许多不同的线程(不是上下文)中的任何地方使用结果.
2,我读了一篇文章说每个线程需要一个上下文,那么在我的情况下,如果它是从API调用回调的话我如何确定它是哪个确切的线程?我真的需要这样做吗?
3,你可能会问为什么我需要一个privateConcurrentType,因为我的程序需要在后台线程中运行,所以它必须这样做,(从其他帖子中读取),这是对的吗?
4,即使在我的问题1中,通过将objectId传递给不同的Context来获取对象仍然不能在我的情况下工作.我们假设这是正确的方法.我怎么能管理在整个程序中在不同的线程中传递这么多的objectID而不是超级凌乱?对我来说这听起来很疯狂,但我想有一个更清洁,更简单的方法来解决这个问题.
5,我已经看了很多帖子都是一些很老的(前迅疾3),他们所要做的childContext.save,然后parentContext.save,但因为我使用上面的代码(SWIFT 3只).似乎我可以做childContext.save只是为了让它工作?我对吗?
核心数据一般不是多线程友好的.要在并发线程上使用它我可以假设只会发生坏事.您可能不会简单地操作上下文所在线程之外的托管对象.
正如您已经提到的,每个线程需要一个单独的上下文,在大多数情况下都可以使用,但根据我的经验,您只需要一个读写的后台上下文和一个用于获取结果控制器或其他的主线程只读上下文即时提取.
将上下文视为与数据库(文件)通信的内存模块.提取的实体在上下文中共享,但不在上下文之间共享.因此,您可以修改上下文中的任何内容,但在将上下文保存到数据库之前,这些内容不会显示在数据库或其他上下文中.如果您在2个上下文中修改相同的实体然后保存它们,您将遇到应该由您解决的冲突.
所有这些都使代码逻辑变得非常混乱,因此多个上下文似乎是要避免的东西.我所做的是创建一个后台上下文,然后对该上下文执行所有操作.Context有一个方法perform,它将在自己的线程上执行代码,该线程不是主要的(对于后台上下文),并且该线程是串行的.
因此,例如在进行智能客户端时,我将从服务器获得具有新条目的响应.这些都是动态解析的,我在上下文中执行一个块来获取数据库中的所有相应对象并创建不存在的对象.然后复制数据并将上下文保存到数据库中.
对于UI部分,我做了类似的事情.一旦保存了一个条目,我就可以在后台上下文线程上创建或更新该实体.然后通常在完成时做一些UI的东西,所以我有一个方法:
public func performBlockOnBackgroundContextAndReturnOnMain(block: @escaping (() -> Void), main: @escaping (() -> Void)) {
if let context = context {
context.perform {
block()
DispatchQueue.main.async(execute: { () -> Void in
main()
})
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以几乎所有核心数据逻辑都发生在后台的单个线程上.在某些情况下,我确实使用主上下文来获取来自获取结果控制器的项目; 我用它显示一个对象列表,一旦用户选择了我从后台上下文中重新获取该项目的项目之一,并在用户界面中使用该项目并进行修改.
但即便如此,也可能会给您带来麻烦,因为某些属性可能会从数据库中延迟加载,因此您必须确保所需的所有数据都将加载到上下文中,您可以在主线程上访问它们.有方法,但我宁愿使用包装器:
对于数据库模型中的所有实体,我只有一个超类id.所以我也有一个超类包装器,它具有与其余包装器一起工作的所有逻辑.我最后留下的是,对于每个子类,我需要覆盖2个映射方法(从和到)托管对象.
创建额外的包装器并将数据从托管对象复制到内存中似乎很愚蠢,但事实上你需要对大多数托管对象执行此操作; 转换NSData为/从UIImage,NSDate从Date/到整数或字符串的枚举...所以最后你或多或少只剩下一对一复制的字符串.此外,这使得在此类或任何其他逻辑中映射来自服务器的响应的代码变得很容易,在这些逻辑中,您将不会与托管对象发生命名冲突.
| 归档时间: |
|
| 查看次数: |
1328 次 |
| 最近记录: |