多上下文核心数据,按关系批量提取

时间:2013-11-05 10:18:48

标签: ios objective-c core-data nsfetchedresultscontroller nsmanagedobjectcontext

问题简而言之

由于没有持久存储协调器的NSManagedObjectContext不支持setFetchBatchSize选择器,我使用了此post的解决方案,它适用于某些问题,我想解决。

enter image description here

这是数据库方案和Coredata结构,括号中的术语。测试应用程序有两个屏幕:包含聊天列表的主表和包含消息列表的详细信息表。主屏幕使用获取控制器中的主MOC来显示表中的数据和工人MOC以创建聊天和消息。详细信息屏幕使用Fetch MOC显示表格中的数据。

在主屏幕上创建一个包含消息的新聊天并通过调用保存在层次结构中的所有MOC上保存后,我无法通过选定的详细聊天屏幕获取消息。我在控制台中获得的是:“CoreData:annotation:总取指执行时间:0行为0.0000秒”。应用程序重启后可以获取此数据。

它似乎与Fetch MOC中的故障消息有关,该故障消息与Chats存在故障关系,该Chats具有与我在Main MOC中的Chats不同的objectID。因为当我在Fetch MOC中获取Chat对象然后用它来查找Messages时,一切正常。

如果有人可以帮我解决这个问题,我会很感激Fetch MOC,或者可以通过我自己的ID字段而不是使用关系来搞定所有Object Graph概念并获取数据。

部分代码

这是在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");
}

以下是我创建工人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。当然,这个选择器在worker 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
  • 我可能稍后添加的其他内容,也很抱歉链接和图片:声誉和愚蠢的东西

1 个答案:

答案 0 :(得分:1)

这是由于一个错误。解决方法是在保存新插入的对象之前调用obtainPermanentIDsForObjects:

有关详细信息,请参阅以下SO问题:

Core Data: Do child contexts ever get permanent objectIDs for newly inserted objects?