5

简而言之有问题

由于没有持久存储协调器的 NSManagedObjectContext 不支持 setFetchBatchSize 选择器,因此我使用了这篇文章中的解决方案,它可以解决某些我想解决的问题。

在此处输入图像描述

这是数据库方案和 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
  • 稍后我可能会添加其他内容,也很抱歉链接和图片:声誉和愚蠢的东西
4

1 回答 1

1

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

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

核心数据:子上下文是否曾经为新插入的对象获得永久对象 ID?

于 2014-01-20T18:54:21.257 回答