Ios 正在设置NSManagedObject属性暂停应用程序。。。有时

Ios 正在设置NSManagedObject属性暂停应用程序。。。有时,ios,core-data,nsmanagedobject,Ios,Core Data,Nsmanagedobject,我有一个应用程序,我循环一些json并在后台设置一些对象 dispatch_async(CD_QUEUE(), ^{ NSEntityDescription *questionEntity = [NSEntityDescription entityForName:QUESTION inManagedObjectContext:self.backgroundContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest

我有一个应用程序,我循环一些json并在后台设置一些对象

dispatch_async(CD_QUEUE(), ^{    

    NSEntityDescription *questionEntity = [NSEntityDescription entityForName:QUESTION inManagedObjectContext:self.backgroundContext];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
    [fetchRequest setEntity:questionEntity];


    for (NSInteger i = 0; i < [questionsArray count]; i++) {

        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"uid == %@", questionUID];
        [fetchRequest setPredicate:predicate];

        NSError *error = nil
        NSArray *array = [context executeFetchRequest:fetchRequest error:&error];
        MYQuestion *question = nil;

        NSLog(@"Error %@",[error localizedDescription]);

        if ([array count] == 0)
        {
            NSLog(@"NIL question");
            question = [self newQuestionInContext:context];
            question.uid = questionUID;
        }
        else
            question = [array objectAtIndex:0];

        if ([questionDataDictionary objectForKey:@"question"] != [NSNull null] && [questionDataDictionary objectForKey:@"question"] != nil)
        {
            NSLog(@"set question %@",question);
            NSLog(@"UID: %@",question.uid);
            question.body = [questionDataDictionary objectForKey:@"question"];
            NSLog(@"set question finished");
        }

 and so on....
dispatch_async(CD_QUEUE(),^{
NSEntityDescription*questionEntity=[NSEntityDescription entityForName:QuestionInManagedObjectContext:self.backgroundContext]中的问题;
NSFetchRequest*fetchRequest=[[NSFetchRequest alloc]init];
[FetchRequestSetEntity:questionEntity];
对于(NSInteger i=0;i<[问题数组计数];i++){
NSPredicate*谓词=[NSPredicate谓词格式:@“uid==%”,questionUID];
[FetchRequestSetPredicate:谓词];
n错误*错误=nil
NSArray*数组=[context executeFetchRequest:fetchRequest错误:&error];
我的问题*问题=零;
NSLog(@“Error%@,[Error localizedDescription]);
如果([数组计数]==0)
{
NSLog(“无问题”);
问题=[self-NewQuestionInText:context];
question.uid=questionUID;
}
其他的
问题=[array objectAtIndex:0];
if([questionDataDictionary objectForKey:@“问题”]!=[NSNull null]&&[questionDataDictionary objectForKey:@“问题”]!=nil)
{
NSLog(@“设置问题%@”,问题);
NSLog(@“UID:%@”,question.UID);
question.body=[questionDataDictionary objectForKey:@“问题”];
NSLog(@“设置问题完成”);
}
等等
有时,每次为同一个问题设置question.body时都会遇到问题,但有时它会在没有问题的情况下完成。问题不是零,正如您所看到的,json对象也不是。那么这里有什么问题呢?我的应用程序在这一点上遇到了问题,我不知道如何解决(如果发生这种情况)

日志

错误(空)

设置问题(实体:MYQuestion;id:0x17641990;数据:


因此,当我尝试访问此对象上的任何属性时,它会出错…提取时没有错误,但该对象有时会出错??我不明白。

这是一个并发问题。通常,
NSManagedObjects
不是线程安全的。这意味着您只能从其
NS的线程读取和写入其属性已创建ManagedObjectContext
,或在此上下文的专用队列中创建

您正在访问
CD\u队列中的托管对象,因此,由Grand Central Dispatch决定在哪个线程中执行此代码。因此,这些托管对象有可能从“错误”线程访问,而不是从其
上下文所在的线程访问

上下文上使用
performBlock
performBlockAndWait
方法之一,而不是
dispatch\u async
。其目的是确保以安全的方式访问托管对象:

[context performBlock:^{
   //do what you did in dispatch_async block
];
如果您想了解更多关于核心数据和并发性的信息,请阅读详细的(尽管有点过时)Apple和


对于问题的第二部分:对象是
错误
并不意味着在获取请求期间出现错误。这意味着对象的属性没有从持久存储加载(如SQLite数据库)到内存。更多信息:

您正在使用不同的上下文。这可能是一个原因吗?是的,使用不同的上下文..虽然看起来不太正确..啊,好吧,很有趣…所以有一个特定的GCD队列本质上是错误的?我拥有它的原因是确保核心数据进程彼此同步。我猜这是我也会这样做,但我如何确保这些进程脱离主线程?通过在BG线程上创建此NSManagedObjectContext,这是否意味着所有这些上下文执行块将随后在该线程上完成?如果要确保核心数据处理在主线程外运行,请创建一个
NSManagedObject上下文
NSPrivateQueueConcurrencyType
。所有块都将在此上下文的专用队列中执行。我不知道此队列是否在同一线程中运行所有这些块(可能不是)-这是一个内部实现详细信息。请确保它们在“安全”环境中运行如果我只有一个backgroundManagedObjectContext和NSPrivateQueueConcurrencyType,那么我希望这些块是同步的。我会试一试。许多感谢我也在想,如果我在CD_队列中包装上下文performBlock,会发生什么?你不必在
调度中包装
performBlock
_async
。此方法正是您想要的:在串行队列中,在后台线程上,一个接一个地执行块。