具有按关系批量获取的多上下文 CoreData
Posted
技术标签:
【中文标题】具有按关系批量获取的多上下文 CoreData【英文标题】:Multi-Context CoreData with batch fetch by relationship 【发布时间】:2013-11-05 10:18:48 【问题描述】:简单的问题
由于没有持久存储协调器的 NSManagedObjectContext 不支持 setFetchBatchSize 选择器,我使用了来自此 post 的解决方案,它适用于某些我想解决的问题。
这是数据库方案和Coredata结构,括号中的术语。测试应用程序有两个屏幕:带有聊天列表的主表和带有消息列表的详细表。主屏幕使用获取控制器中的 Main MOC 来显示表中的数据,并使用 Worker MOC 来创建聊天和消息。详情屏幕使用 Fetch MOC 来显示表格中的数据。
在我在主屏幕上创建一个带有消息的新聊天并在层次结构中的所有 MOC 上调用 save 来保存它们后,我无法通过选定的详细聊天屏幕获取消息。我在控制台中得到的只是:“CoreData:注释:总提取执行时间:0 行 0.0000 秒”。应用重启后可以获取这些数据。
这似乎与 Fetch MOC 中的错误消息有关,该错误消息与具有与我在 Main MOC 中的聊天不同的 objectID 的聊天有故障关系。因为当我在 Fetch MOC 中获取 Chat 对象,然后使用它来查找消息时,一切正常。
如果有人可以帮助我使用 Fetch MOC 解决此问题,或者使用我自己的 ID 字段而不是使用关系来获取所有对象图概念并获取数据,我将不胜感激。
一些代码
这是在 didFinishLaunchingWithOptions 上完成的 Coredata 堆栈初始化:
- (void)initializeCoreDataStack
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"FaultsFetching" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_managedObjectModel];
_writerMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_writerMOC setUndoManager:nil];
[_writerMOC setPersistentStoreCoordinator:_persistentStoreCoordinator];
_mainThreadMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_mainThreadMOC setUndoManager:nil];
[_mainThreadMOC setParentContext:_writerMOC];
_fetchMainThreadMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_fetchMainThreadMOC setUndoManager:nil];
[_fetchMainThreadMOC setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
[_fetchMainThreadMOC setPersistentStoreCoordinator:_persistentStoreCoordinator];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:_writerMOC];
NSURL *storeURL = [APP_DOC_DIR URLByAppendingPathComponent:@"FaultsFetching.sqlite"];
NSError *error = nil;
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
- (void)backgroundContextDidSave:(NSNotification *)notification
[_fetchMainThreadMOC mergeChangesFromContextDidSaveNotification:notification];
NSLog(@"Yep, everything is merged");
这是我创建 Worker MOC 的方法:
+ (NSManagedObjectContext *)createPrivateMOC
CoreDataManager *scope = [CoreDataManager sharedInstance];
NSManagedObjectContext *workerMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
workerMOC.parentContext = scope.mainThreadMOC;
[workerMOC setUndoManager:nil];
workerMOC.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
return workerMOC;
这是多上下文保存的样子。参数 async 是 YES。自然地,这个选择器在工作者 MOC 的 performBlock 选择器中被调用
+ (void)writeToDiskAsync:(BOOL)async
CoreDataManager *scope = [CoreDataManager sharedInstance];
NSManagedObjectContext *writeManagedObjectContext = scope.writerMOC;
NSManagedObjectContext *mainManagedObjectContext = scope.mainThreadMOC;
PerformBlock mainMOCBlock = ^
NSError *mainError = nil;
if ([mainManagedObjectContext hasChanges] && ![mainManagedObjectContext save:&mainError])
ALog(@"Unresolved error %@, %@", mainError, [mainError userInfo]);
PerformBlock writerBlock = ^
NSError *writeError = nil;
if ([writeManagedObjectContext hasChanges] && ![writeManagedObjectContext save:&writeError])
ALog(@"Unresolved error %@, %@", writeError, [writeError userInfo]);
NSLog(@"Yep, everything is saved");
;
[scope performBlock:writerBlock onMOC:writeManagedObjectContext async:async];
;
[scope performBlock:mainMOCBlock onMOC:mainManagedObjectContext async:async];
- (void)performBlock:(PerformBlock)block onMOC:(NSManagedObjectContext *)target async:(BOOL)async
if (async)
[target performBlock:block];
else
[target performBlockAndWait:block];
这是我在详细屏幕上的获取结果控制器,其中“detailItem”是从主屏幕设置的聊天实体,“[CoreDataManager sharedInstance]”是单例:
- (NSFetchedResultsController *)fetchedResultsController
if (_fetchedResultsController != nil)
return _fetchedResultsController;
if (self.detailItem == nil)
return nil;
NSManagedObjectContext *fetchMOC = [CoreDataManager sharedInstance].fetchMainThreadMOC;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Messages" inManagedObjectContext:fetchMOC];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"sentDate" ascending:NO];
[fetchRequest setSortDescriptors:@[sortDescriptor]];
NSPredicate *chatPredicate = [NSPredicate predicateWithFormat:@"relatedChat=%@", self.detailItem.objectID];
[fetchRequest setPredicate:chatPredicate];
_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:fetchMOC sectionNameKeyPath:@"sectionIdentifier" cacheName:nil];
_fetchedResultsController.delegate = self;
NSError *error = nil;
if (![_fetchedResultsController performFetch:&error])
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
return _fetchedResultsController;
一点背景
父/子 MOC 用于提高从一开始就没有正确编写的应用程序的稳定性和响应能力。但是,由于现在与 Coredata 相关的一切都或多或少是中心化的,因此可以将堆栈更改为不同的东西。 SectionIdentifier 用于按天对消息进行分组,如下所示:http://i.imgur.com/17tuKS7.png 稍后我可能会添加其他内容,也很抱歉链接和图片:声誉和愚蠢的东西【问题讨论】:
你在线程中使用了任何worker MOC吗? 我在主屏幕上的 IBAction 选择器的按钮触摸上使用工人 MOC 来创建聊天及其消息。我在工人 MOC 上使用 performBlock 选择器 我可以看到你在同一个线程中创建所有的 MOC,所以我想知道你是否在其他线程中使用它们中的任何一个,因为如果你是,你会在保存和获取时遇到问题。 这应该不是问题,因为我将所有数据保存在一系列 performBlock 调用中,我会将此代码添加到问题中。 会不会和这个问题有关? ***.com/questions/11990279/…。如果在保存新插入的对象之前调用 gainPermanentIDsForObjects: 会有所不同吗? 【参考方案1】:这是由于一个错误。解决方法是在保存新插入的对象之前调用obtainPermanentIDsForObjects:
。
有关详细信息,请参阅以下 SO 问题:
Core Data: Do child contexts ever get permanent objectIDs for newly inserted objects?
【讨论】:
我很好奇这个 gainPermanentIDsForObjects: 是否是一个昂贵的操作,我是否应该为所有插入的对象调用它 听起来只有在某些情况下才需要在子上下文中保存插入的对象之前。它确实需要与商店通信,因此会在主线程上引起一些循环。我会在您遇到问题的情况下使用它。以上是关于具有按关系批量获取的多上下文 CoreData的主要内容,如果未能解决你的问题,请参考以下文章