Core data 在串行NSOperationQueue上初始化NSManagedObjectContext

Core data 在串行NSOperationQueue上初始化NSManagedObjectContext,core-data,nsmanagedobjectcontext,nsoperation,nsoperationqueue,Core Data,Nsmanagedobjectcontext,Nsoperation,Nsoperationqueue,我有一个NSOperationQueue,其中添加了一些NSBlockOperations,其中包括blockOperations A和B。NSOperationQueue的maxConcurrencyOperationCount为1 阻塞操作B取决于A是否完成。在每个块操作中,我调用一个方法,该方法反过来调用另一个方法,该方法初始化一个新的NSManagedObjectContext(使用singleton中的persistentStoreCoordinator),我使用该方法创建对象并将其添

我有一个
NSOperationQueue
,其中添加了一些
NSBlockOperations
,其中包括blockOperations A和B。
NSOperationQueue
maxConcurrencyOperationCount
为1

阻塞操作B取决于A是否完成。在每个块操作中,我调用一个方法,该方法反过来调用另一个方法,该方法初始化一个新的
NSManagedObjectContext
(使用singleton中的persistentStoreCoordinator),我使用该方法创建对象并将其添加到核心数据数据库中。前面提到的A和B中的第二个方法调用调用的代码如下所示(每个方法调用的代码略有不同):

saveContext:
代码如下所示:

NSError *error = nil;
if (managedObjectContext != nil) {
    if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    }
}
在花了大量时间阅读苹果公司关于核心数据并发性、NSOperation等方面的文档之后,我仍然不确定我使用NSManagedObjectContext所做的是否是线程安全的,并且通常认为是可以的?如果能澄清和/或表明我应该采取不同的做法,我将不胜感激。如果您需要查看更多代码,请询问


提前感谢。

上下文的问题是它只能在单个线程中访问。设置MaxConcurrencyOperationCount并不能保证这一点。另一种方法是将上下文设置为“thread”变量,在使用上下文的每个线程字典中存储上下文

例:


上下文的问题是,它只能在单个线程中访问。设置MaxConcurrencyOperationCount并不能保证这一点。另一种方法是将上下文设置为“thread”变量,在使用上下文的每个线程字典中存储上下文

例:


您所做的不是线程安全的。

如果决定为每个操作创建一个上下文,最好使用限制并发类型:

context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
这样,您就不需要更改当前代码中的任何内容

如果要将上下文与
NSPrivateQueueConcurrencyType
一起使用,则必须通过
performBlock:
performBlockAndWait:
访问该上下文中的对象:

[managedObjectContext performBlockAndWait:^{//wait is used as to not end the operation before this code is executed
    for (NSDictionary *articleDictionary in array) {
        if (![Article articleExistsWithIDInDictionary:articleDictionary
                                            inContext:managedObjectContext]) 
        {
            [Article articleFromDictionary:articleDictionary 
                                 inContext:managedObjectContext];
        }
    }
}];
对于你的情况,我可能会选择我的第一个解决方案。

综上所述,您可以简单地使用“专用队列”上下文作为串行队列(只要您按照需要执行的顺序向其添加块操作)。
上下文
performBlock:
方法将对块进行排队,并针对添加该上下文以在后台执行的其他块串行执行它:

//add this to your CoreDataController
context = [[CoreDataController sharedCoreDataController] serialExecutionBGContext];
[context performBlock:^{ //your block operation code1}];
[context performBlock:^{ //your block operation code2}];
这将在后台连续执行代码1和代码2。

通过这种方式,您可以节省分配新上下文的开销,并且可以从该上下文完成的缓存中获益。

您可能希望不时重置此上下文,以便它不会因获取的对象而膨胀。

您所做的不是线程安全的。

如果决定为每个操作创建一个上下文,最好使用限制并发类型:

context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
这样,您就不需要更改当前代码中的任何内容

如果要将上下文与
NSPrivateQueueConcurrencyType
一起使用,则必须通过
performBlock:
performBlockAndWait:
访问该上下文中的对象:

[managedObjectContext performBlockAndWait:^{//wait is used as to not end the operation before this code is executed
    for (NSDictionary *articleDictionary in array) {
        if (![Article articleExistsWithIDInDictionary:articleDictionary
                                            inContext:managedObjectContext]) 
        {
            [Article articleFromDictionary:articleDictionary 
                                 inContext:managedObjectContext];
        }
    }
}];
对于你的情况,我可能会选择我的第一个解决方案。

综上所述,您可以简单地使用“专用队列”上下文作为串行队列(只要您按照需要执行的顺序向其添加块操作)。
上下文
performBlock:
方法将对块进行排队,并针对添加该上下文以在后台执行的其他块串行执行它:

//add this to your CoreDataController
context = [[CoreDataController sharedCoreDataController] serialExecutionBGContext];
[context performBlock:^{ //your block operation code1}];
[context performBlock:^{ //your block operation code2}];
这将在后台连续执行代码1和代码2。

通过这种方式,您可以节省分配新上下文的开销,并且可以从该上下文完成的缓存中获益。

您可能需要不时重置此上下文,这样它就不会因为获取的对象而变得臃肿。

Hi Dan,谢谢您提供了非常翔实的答案。你能澄清一下“重置此上下文”的含义吗?NSManagedObjectContext上是否有重置方法?另外,如果按顺序执行
performBlock:
,则
performBlock:
performBlockAndWait:
之间有什么区别?是的,
NSManagedObjectContext
上有一个
reset
方法,可以将上下文中断获取的对象绑定到上下文。当您不再需要在上下文中获取现有数据,但仍希望保留上下文时,这是回收内存的一种好方法
performBlock
不是串行执行的,它串行地对执行块进行排队,它是异步执行的,不阻塞当前线程(与它的
andWait
对应线程不同)。通常情况下,一个上下文会对其自身串行执行其执行的块。Hi Dan,您说过“一个context performBlock:方法会对该块进行排队,并对添加了该上下文以在后台执行的其他块串行执行它:”但我在文档中找不到这一点。您在哪里读到队列是串行的?通常,NSOperationQueue默认情况下不是串行的,我们必须写入“queue.maxConcurrentOperationCount=1”以使其串行。谢谢。@superpuccio我不确定它是否能在官方文档中找到,但我能找到上下文使用串行队列的状态Hi Dan,谢谢你提供了非常翔实的答案。你能澄清一下“重置此上下文”的含义吗?NSManagedObjectContext上是否有重置方法?另外,如果按顺序执行
performBlock:
,则
performBlock:
performBlockAndWait:
之间有什么区别?是的,
NSManagedObjectContext
上有一个
reset
方法,使上下文拒绝获取对象