- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我已经阅读了一些关于此的博客,但我仍然对如何使用 NSPersistentContainer performBackgroundTask
创建实体并保存它感到困惑。通过在 performBackgroundTask() { (moc) in }
block 中调用便利方法 init(context moc: NSManagedObjectContext)
创建实例后,如果我检查 container.viewContext。 hasChanges
这会返回 false 并表示没有要保存的内容,如果我在 moc
(为此 block 创建的背景 MOC)上调用保存,我会收到如下错误:
fatal error: Failure to save context: Error Domain=NSCocoaErrorDomain Code=133020 "Could not merge changes." UserInfo={conflictList=(
"NSMergeConflict (0x17466c500) for NSManagedObject (0x1702cd3c0) with objectID '0xd000000000100000 <x-coredata://3EE6E11B-1901-47B5-9931-3C95D6513974/Currency/p4>' with oldVersion = 1 and newVersion = 2 and old cached row = {id = 2; ... }fatal error: Failure to save context: Error Domain=NSCocoaErrorDomain Code=133020 "Could not merge changes." UserInfo={conflictList=(
"NSMergeConflict (0x170664b80) for NSManagedObject (0x1742cb980) with objectID '0xd000000000100000 <x-coredata://3EE6E11B-1901-47B5-9931-3C95D6513974/Currency/p4>' with oldVersion = 1 and newVersion = 2 and old cached row = {id = 2; ...} and new database row = {id = 2; ...}"
)}
所以我未能使并发工作,如果有人能向我解释在 iOS 10 中对核心数据使用此功能的正确方法,我将不胜感激
最佳答案
TL:DR:您的问题是您在编写时同时使用了 viewContext
和背景上下文。您应该只以一种同步方式写入核心数据。
完整解释:如果一个对象同时从两个不同的上下文中更改,则核心数据不知道该怎么做。您可以设置一个 mergePolicy 来设置哪个更改应该获胜,但这确实不是一个好的解决方案,因为那样您会丢失数据。许多专业人士长期以来处理这个问题的方法是有一个操作队列来对写入进行排队,这样一次只有一个写入在进行,并且在主线程上有另一个上下文只用于读取.这样你就永远不会遇到任何合并冲突。 (有关此设置的详细解释,请参阅 https://vimeo.com/89370886#t=4223s)。
使用 NSPersistentContainer
进行此设置非常简单。在你的核心数据管理器中创建一个 NSOperationQueue
//obj-c
_persistentContainerQueue = [[NSOperationQueue alloc] init];
_persistentContainerQueue.maxConcurrentOperationCount = 1;
//swift
let persistentContainerQueue = OperationQueue()
persistentContainerQueue.maxConcurrentOperationCount = 1
并使用此队列进行所有写入:
// obj c
- (void)enqueueCoreDataBlock:(void (^)(NSManagedObjectContext* context))block{
void (^blockCopy)(NSManagedObjectContext*) = [block copy];
[self.persistentContainerQueue addOperation:[NSBlockOperation blockOperationWithBlock:^{
NSManagedObjectContext* context = self.persistentContainer.newBackgroundContext;
[context performBlockAndWait:^{
blockCopy(context);
[context save:NULL]; //Don't just pass NULL here, look at the error and log it to your analytics service
}];
}]];
}
//swift
func enqueue(block: @escaping (_ context: NSManagedObjectContext) -> Void) {
persistentContainerQueue.addOperation(){
let context: NSManagedObjectContext = self.persistentContainer.newBackgroundContext()
context.performAndWait{
block(context)
try? context.save() //Don't just use '?' here look at the error and log it to your analytics service
}
}
}
当您调用 enqueueCoreDataBlock
时,该 block 将入队以确保没有合并冲突。但是,如果您写入 viewContext
将会破坏此设置。同样,您应该将您创建的任何其他上下文(使用 newBackgroundContext
或使用 performBackgroundTask
)视为只读的,因为它们也不在写入队列中。
起初我以为 NSPersistentContainer
的 performBackgroundTask
有一个内部队列,初步测试支持这一点。经过更多测试后,我发现它也可能导致合并冲突。
关于ios - 用于保存到核心数据的 NSPersistentContainer 并发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42733574/
注意:我看过类似的问题,但没有找到描述这种情况的问题。 我正在查看以下来自 Apple 的有关核心数据并发性 (https://developer.apple.com/library/content/
我正在创建一个 NSPersistentContainer 来保存一些数据,但即使在上下文中调用 save() 也不会创建任何数据库文件。 我用来创建 NSPersistentContainer 的代
我创建了一个单例类来管理我的核心数据: class CoreDataManager { static let sharedManager = CoreDataManager() private ini
当我通过这段代码自己创建容器时,在应用程序支持文件夹中会创建什么样的持久存储? private lazy var storeContainer: NSPersistentContainer = {
我像这样创建一个 NSPersistentContainer: static let persistentContainer: NSPersistentContainer = { let c
我刚刚添加了一个选项,供用户在我的应用程序中切换云同步,我保存用户是否要在“useCloudSync”下的 UserDefaults 中使用 iCloud 同步。当应用程序运行时,我加载我的persi
我正在熟悉 NSPersistentContainer .我想知道使用 newBackgroundContext 生成私有(private)上下文的实例是否更好。每次我需要在后台插入/获取一些实体或创
我刚刚在 Core Data 上设置了一个只读数据存储。它可以工作,但编译器对此有提示,我想知道如何解决这个问题。 这里的相关代码是我在Xcode自动生成模板后修改的。 lazy var persis
我在一些地方(例如 a high score answer here )读到,将主托管上下文作为后台托管上下文的子级是一种很好的做法,可以节省 save() 时间并提高 UI 响应能力。 Persis
我已经阅读了一些关于此的博客,但我仍然对如何使用 NSPersistentContainer performBackgroundTask 创建实体并保存它感到困惑。通过在 performBackgro
我正在使用 NSPersistentContainer 来创建我的核心数据堆栈。 documentation说我们应该使用它的 viewContext 属性来获取主要的 NSManagedObject
使用在主队列上运行的 NSManagedObjectContext 和在私有(private)队列上运行的辅助 NSManagedObjectContext 并让它们共享一个 NSPersistent
我的单元测试核心数据设置有问题。 我在我的 AppDelegate 中使用默认/新的核心数据堆栈设置 class AppDelegate: UIResponder, UIApplicationDele
我收到一个错误: AppDelegate has no member persistentContainer import UIKit import CoreData class ViewContro
在Apple的NSPersistentContainer文档中,该方法有如下描述: func loadPersistentStores(completionHandler block: @escapi
我的 AppDelegate 带有以下所有熟悉的核心数据模板: lazy var persistentContainer: NSPersistentContainer = { let cont
现在所有核心数据示例都是 iOS 示例,因此自从 macOS 10.12 中对核心数据进行了有趣的更改以来,对于 macOS 没有太多指导。但我想看看 NSPercientContainer 应该如何
在当前运行的 App Store 应用程序中,我使用 MagicalRecord 来设置我的核心数据。当我遇到并发问题时,我四处寻找解决方案。我意识到自从引入 iOS 10 以来,Core Data
我无法将令人兴奋的核心数据堆栈更改为 NSPersistentCloudKitContainer,因为这只是 iOS 13 及更高版本的支持功能,但我希望为 iOS 13 及更高版本设置该设置,同时为
我确信这个问题会被问到并回答很多次,但我惊讶地发现,经过数小时的搜索,我找不到答案。随着 iOS 10 的到来,NSPersistentContainer 改变了我们处理 Core Data Stac
我是一名优秀的程序员,十分优秀!