0

我目前正在尝试实施方案:

MOC1 (PrivateQueue) -parent-> MOC2 (MainQueue) -parent-> MOC3 (PrivateQueue), PSC 保存

这是初始化代码(MOC2 & MOC#:

_writeManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
_writeManagedObjectContext.persistentStoreCoordinator = coordinator;
_writeManagedObjectContext.undoManager = nil;

_mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
_mainManagedObjectContext.undoManager = nil;
_mainManagedObjectContext.parentContext = _writeManagedObjectContext;

这是初始化 MOC1:

    _mocSSchild = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    _mocSSchild.undoManager = nil;
    _mocSSchild.parentContext = delegateMain.mainManagedObjectContext;

这是一个保存:

    NSError *error = nil;
    [self.mocSSchild obtainPermanentIDsForObjects:self.mocSSchild.insertedObjects.allObjects error:&error];

    if (![self.mocSSchild save: &error]) {
    NSLog(@"Failed to save to FIRST data store: %@", [error localizedDescription]);
    NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
    if(detailedErrors != nil && [detailedErrors count] > 0)
    {
        for(NSError* detailedError in detailedErrors)
        {
            NSLog(@"  DetailedError: %@", [detailedError userInfo]);
        }
    }
    else
    {
        NSLog(@"  %@", [error userInfo]);
    }

    }
    AppDelegate *delegateMain = (AppDelegate *)[[NSApplication sharedApplication] delegate];
    if ([delegateMain.mainManagedObjectContext hasChanges] && ![delegateMain.mainManagedObjectContext save: &error]) {        NSLog(@"Failed to save to FIRST data store: %@", [error localizedDescription]);
    NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
    if(detailedErrors != nil && [detailedErrors count] > 0)
    {
        for(NSError* detailedError in detailedErrors)
        {
            NSLog(@"  DetailedError: %@", [detailedError userInfo]);
        }
    }
    else
    {
        NSLog(@"  %@", [error userInfo]);
    }
}
    if ([delegateMain.writeManagedObjectContext hasChanges] && ![delegateMain.writeManagedObjectContext save: &error]) {        NSLog(@"Failed to save to FIRST data store: %@", [error localizedDescription]);
    NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
    if(detailedErrors != nil && [detailedErrors count] > 0)
    {
        for(NSError* detailedError in detailedErrors)
        {
            NSLog(@"  DetailedError: %@", [detailedError userInfo]);
        }
    }
    else
    {
        NSLog(@"  %@", [error userInfo]);
    }
}

所有获取请求都放在正确的块中(当然我从不接触 mainManagedObjectContext 来执行获取请求):

    __block NSError *error = nil;
    __block NSArray *findedResult = nil;
    [self.mocSSchild performBlockAndWait:^{
        findedResult = [self.mocSSchild executeFetchRequest:fetchRequest error:&error];
    }];

一次保存后,我在主队列中冻结(看起来核心数据尝试在我不执行请求的 mainManagedObjectContext 上执行获取请求):

Call graph:
    2633 Thread_803320   DispatchQueue_173: NSManagedObjectContext Queue  (serial)
    + 2633 start  (in libdyld.dylib) + 1  [0x7fff8bb907e1]
    +   2633 main  (in callsfreecall) + 34  [0x10992c202]
    +     2633 NSApplicationMain  (in AppKit) + 869  [0x7fff8a49cbd6]
    +       2633 -[NSApplication run]  (in AppKit) + 517  [0x7fff8a4f81a3]
    +         2633 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]  (in AppKit) + 128  [0x7fff8a500df2]
    +           2633 _DPSNextEvent  (in AppKit) + 685  [0x7fff8a501533]
    +             2633 BlockUntilNextEventMatchingListInMode  (in HIToolbox) + 62  [0x7fff8f356ae3]
    +               2633 ReceiveNextEventCommon  (in HIToolbox) + 356  [0x7fff8f356c52]
    +                 2633 RunCurrentEventLoopInMode  (in HIToolbox) + 209  [0x7fff8f356eb4]
    +                   2633 CFRunLoopRunSpecific  (in CoreFoundation) + 290  [0x7fff9526c0e2]
    +                     2633 __CFRunLoopRun  (in CoreFoundation) + 1644  [0x7fff9526cb4c]
    +                       2633 _dispatch_main_queue_callback_4CF  (in libdispatch.dylib) + 275  [0x7fff8c4c20c8]
    +                         2633 _dispatch_client_callout  (in libdispatch.dylib) + 8  [0x7fff8c4bd0b6]
    +                           2633 _dispatch_barrier_sync_f_slow_invoke  (in libdispatch.dylib) + 77  [0x7fff8c4c2a2d]
    +                             2633 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke_0  (in CoreData) + 533  [0x7fff93d8b6c5]
    +                               2633 -[NSManagedObjectContext countForFetchRequest:error:]  (in CoreData) + 1563  [0x7fff93d65ddb]
    +                                 2633 -[NSManagedObjectContext(_NSInternalAdditions) _countWithNoChangesForRequest:error:]  (in CoreData) + 298  [0x7fff93d65f4a]
    +                                   2633 -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]  (in CoreData) + 354  [0x7fff93d576c2]
    +                                     2633 _perform  (in CoreData) + 172  [0x7fff93d5787c]
    +                                       2633 _dispatch_barrier_sync_f_invoke  (in libdispatch.dylib) + 39  [0x7fff8c4be723]
    +                                         2633 _dispatch_client_callout  (in libdispatch.dylib) + 8  [0x7fff8c4bd0b6]
    +                                           2633 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke_0  (in CoreData) + 533  [0x7fff93d8b6c5]
    +                                             2633 -[NSManagedObjectContext countForFetchRequest:error:]  (in CoreData) + 1563  [0x7fff93d65ddb]
    +                                               2633 -[NSManagedObjectContext(_NSInternalAdditions) _countWithNoChangesForRequest:error:]  (in CoreData) + 298  [0x7fff93d65f4a]
    +                                                 2633 -[NSPersistentStoreCoordinator executeRequest:withContext:error:]  (in CoreData) + 1138  [0x7fff93d10ba2]
    +                                                   2633 -[_PFLock lock]  (in CoreData) + 24  [0x7fff93cfe548]
    +                                                     2633 pthread_mutex_lock  (in libsystem_c.dylib) + 536  [0x7fff92797dfd]
    +                                                       2633 __psynch_mutexwait  (in libsystem_kernel.dylib) + 10  [0x7fff938ca122]
4

1 回答 1

1

首先,当您收到错误时,您需要对错误进行处理。现在你什么都没有做,没有记录它们,没有对它们做出反应,什么都没有。这是不好的。当发生错误时,您根本没有任何迹象。您只需进行下一步。

其次,您将所有 MOC 保存在同一个队列中。任何针对私有 MOC 的活动都必须通过-performBlock:or-performBlockAndWait:方法在块内执行。

第三,没有迹象表明您正在运行哪个队列。

您的导入 MOC 应该在操作或异步运行的块内运行。导入 MOC 应该使用线程限制而不是私有 MOC。一旦导入 MOC 完成其工作,它应该保存自己,然后向主队列指示应该保存主 MOC。

主 MOC 应该只保存在主队列中。当主 MOC 完成保存后,它应该通过其-performBlock:.

通过错误结果更正您的问题,并查看您正在处理哪些队列。如果一切都在主队列上,那么父/子 MOC 将无法解决您的问题。您需要重新考虑在哪里执行了哪些工作。

更新 1

首先,您可以通过侦听调用的结果来检测错误。如果调用返回 aBOOL则表示通过/失败。如果调用返回其他东西,那么如果是其他东西,nil那么这就是失败并且将出现错误。

至于您的代码,不,它不正确。正如我提到的,你有线程问题。您正在直接接触私人 MOC,这是不正确的。可能还有其他错误,但根据此代码我看不到它们。

您的“写作” MOC 只能通过 a-performBlock:-performBlockAndWait:. 在这种情况下,您应该使用-performBlock:. 你直接触摸它。那很不好。

您的主 MOC 只能在主队列上或通过-performBlock:/被触及-performBlockAndWait:。您似乎在此代码中直接触摸它。

您正在appDelegate以单身身份访问您的。这是一种糟糕的代码气味。查找并开始使用依赖注入。

当你的子 moc 应该是一个线程受限的上下文时,它被设置为私有的,然后它只能在创建它的线程上访问,理想情况下应该在 NSOperation 中。

简而言之,这里缺少很多核心概念。在尝试开发这样的代码之前,您需要了解父/子上下文是如何工作的,并且需要更好地了解队列和线程。

于 2013-06-26T22:14:59.347 回答