BBr*_*uce 3 concurrency core-data ios
我一直在iOS 10中测试新的核心数据堆栈.我的测试应用程序将JSON数据解析为核心数据,我试图在用户访问UI时实现这一点.
我使用默认核心数据堆栈并使用后台上下文.
在AppDelegate.m中:
- (NSPersistentContainer *)persistentContainer {
// The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
@synchronized (self) {
if (_persistentContainer == nil) {
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"CoreDataTestingMDC"];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
abort();
}
}];
}
}
_persistentContainer.viewContext.automaticallyMergesChangesFromParent = YES;
return _persistentContainer;
}
Run Code Online (Sandbox Code Playgroud)
我有一个简单的主从细节UI,它显示主视图控制器中的核心数据实体和详细视图中的详细属性.如果用户没有滚动主视图,一切正常.如果用户滚动,我通常会在保存时出现此错误:
Unresolved error Error Domain=NSCocoaErrorDomain Code=133020 "(null)" UserInfo={conflictList=(
"NSMergeConflict (0x600000667c00) for NSManagedObject (0x610000096490) with objectID '0xd000000000440000 <x-coredata://CFF27A51-8F9E-4898-A4EA-CD85C0AFF300/ContentItem/p17>'
with oldVersion = 44 and newVersion = 45...
Run Code Online (Sandbox Code Playgroud)
它继续列出具有完全相同属性的冲突项.
同样在我的AppDelegate中,我添加了一个简单的方便方法来生成背景上下文:
- (NSManagedObjectContext *)createBackgroundContext {
return [self.persistentContainer newBackgroundContext];
}
Run Code Online (Sandbox Code Playgroud)
这将传递回AppDelegate以进行保存操作:
- (void)saveContext:(NSManagedObjectContext *) theContext {
NSError *error = nil;
if ([theContext hasChanges] && ![theContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
abort();
}
}
Run Code Online (Sandbox Code Playgroud)
UI按预期在viewContext上运行.我一直非常小心地使用背景上下文来编写所有JSON解析器.不知道为什么会崩溃.
更新:
看起来每当应用程序在初始运行后运行时都会发生错误.我可以在干净的模拟器上或删除应用程序后测试它.它可以很好地将数据解析为核心数据,并在用户与应用程序交互时进行更新.在第二次构建和运行时,应用程序将崩溃并出现上述错误.
在我看来,你正在同时进行多次写入.要解决此问题,您需要以单一同步方式写入核心数据.
在核心数据管理器中创建一个NSOperationQueue
_persistentContainerQueue = [[NSOperationQueue alloc] init];
_persistentContainerQueue.maxConcurrentOperationCount = 1;
Run Code Online (Sandbox Code Playgroud)
并使用此队列写所有内容:
- (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
}];
}]];
}
Run Code Online (Sandbox Code Playgroud)
当您调用enqueueCoreDataBlock块时,队列将确保没有合并冲突.但是,如果你写的viewContext那将打败这个设置.同样,您应该将您创建的任何其他上下文(with newBackgroundContext或with performBackgroundTask)视为readonly,因为它们也将在写入队列之外.
起初我以为 NSPersistentContainer的performBackgroundTask有一个内部队列,并初步测试支持这一点.经过更多测试后,我发现它也可能导致合并冲突.
| 归档时间: |
|
| 查看次数: |
1955 次 |
| 最近记录: |