如何通过创建本地上下文将 GCD 与 Core Data 一起使用

Posted

技术标签:

【中文标题】如何通过创建本地上下文将 GCD 与 Core Data 一起使用【英文标题】:How to use GCD with Core Data by creating local context 【发布时间】:2015-09-03 05:59:15 【问题描述】:

我正在尝试处理项目并将其与 coredata 和 GCD 一起存储。我正在将 mainContext 复制到 localContext。我还没有到达合并部分,但它一直在我身上崩溃。这是我的代码:

dispatch_queue_t coreQueue = dispatch_queue_create("coreQueue", DISPATCH_QUEUE_CONCURRENT);

NSMutableSet __block *sumManagedObjects=[NSMutableSet set];

int processorCount = (int) [[NSProcessInfo processInfo] processorCount];

int __block limit = ceil((float)recordsToCreate.count/processorCount);
int loopCount = ceil((float)recordsToCreate.count/limit);
dispatch_apply(processorCount, coreQueue, ^(size_t i) 

    int startIndex = ((int)i)*limit;
    int maxIndex = (int)recordsToCreate.count;
    int endIndex = (startIndex + limit) < maxIndex ? (startIndex + limit) : maxIndex;
    int range = endIndex - startIndex;

    NSManagedObjectContext *localContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
    [localContext setParentContext:self.mainContext];

NSSet *createdObjects=  [localContext insertWithEntityName:self.entityName withDataObjects:[NSSet setWithArray:[recordsToCreate subarrayWithRange:NSMakeRange(startIndex, range)]]];

 dispatch_async(dispatch_get_main_queue(), ^

        [sumManagedObjects unionSet:createdObjects];
         NSLog(@"managed objects %tu start index %d end index %d size_t : %d, sum managed object : %tu thread %@", [createdObjects count], startIndex, endIndex, (int)i, [sumManagedObjects count], [NSThread currentThread]);
        if([sumManagedObjects count] == recordsToCreate.count) 
            [sumManagedObjects setValue:@YES forKey:ItemAttribute.someKey];[context save:nil];


                        

    );

这是更新后的代码:

dispatch_queue_t coreQueue = dispatch_queue_create("coreQueue", DISPATCH_QUEUE_CONCURRENT);

NSMutableSet __block *sumManagedObjects=[NSMutableSet set];

int processorCount = 8;

int __block limit = ceil((float)recordsToCreate.count/processorCount);
int loopCount = ceil((float)recordsToCreate.count/limit);

NSLog(@"int count %d, record to create %tu", loopCount, recordsToCreate.count);

dispatch_apply(processorCount, coreQueue, ^(size_t i) 

    int startIndex = ((int)i)*limit;
    int maxIndex = (int)recordsToCreate.count;
    int endIndex = (startIndex + limit) < maxIndex ? (startIndex + limit) : maxIndex;
    int range = endIndex - startIndex;

     NSManagedObjectContext *privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [privateManagedObjectContext setPersistentStoreCoordinator:self.mainContext.persistentStoreCoordinator];
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    [nc addObserver:self selector:@selector(managedObjectContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:privateManagedObjectContext];

    [privateManagedObjectContext insertWithEntityName:self.entityName withDataObjects:[NSSet setWithArray:[recordsToCreate subarrayWithRange:NSMakeRange(startIndex, range)]]];

    NSLog(@"current thread %@ start index %tu end index %tu size_t : %d", [NSThread currentThread], startIndex, endIndex, (int)i );


    dispatch_async(dispatch_get_main_queue(), ^
        if(self.cancelled) return;

        [privateManagedObjectContext performBlockAndWait:^
            NSError *error = nil;
            privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
            BOOL success = [privateManagedObjectContext save:&error];
            if (!success) 
                NSLog(@"%@", error);
            
        ];



    );

);

- (void)managedObjectContextDidSave:(NSNotification *)notification 

[self.mainContext performBlockAndWait:^
if(self.cancelled) return;
dispatch_async(dispatch_get_main_queue(), ^
    if(self.cancelled) return;
    [self.mainContext mergeChangesFromContextDidSaveNotification:notification ];
);
];

现在我收到此错误: 由于未捕获的异常“NSGenericException”而终止应用程序,原因:“*** Collection <__nscfset:> 在枚举时发生了变异。”

有什么想法吗?我是否正确阻止了资源?谢谢!

【问题讨论】:

核心数据中的限制支持已被弃用。您应该使用核心数据performBlock API 来管理线程之间的同步。 【参考方案1】:

您不能在后台线程上更新限制上下文,然后将托管对象结果传回主线程以进行另一次更新并保存上下文。所有更新和上下文保存都需要在后台线程上完成。这就是坐月子的意思,你需要遵守那个坐月子的规则。

【讨论】:

我已经更新了我的代码,但它仍然崩溃。现在我收到此错误:由于未捕获的异常“NSGenericException”而终止应用程序,原因:“*** Collection <__nscfset:> 在枚举时发生了变异。”请在原始帖子中查看我更新的代码。谢谢!

以上是关于如何通过创建本地上下文将 GCD 与 Core Data 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

iOS:将 GCD 与 Core Data 结合使用

FAQHMS Core推送服务与本地创建通知消息如何相互覆盖?

798C - Mike and gcd problem

在 iOS 中传递上下文以将 Core Data 与 Storyboard 一起使用

.net core 添加本地dll

Core Data - 如何在不同的上下文中建立两个对象之间的关系