设置NSManagedObject属性会暂停app ...有时候

时间:2014-11-24 15:42:04

标签: ios core-data nsmanagedobject

我有一个应用程序,我循环一些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....

有时这会在每次为同一个问题设置问题时遇到困难,但有时它会在没有问题的情况下完成。问题不是零,因为你不能看到json对象..所以这里有什么问题?我的应用程序在此时陷入困境,我不知道如何解决这个问题(如果它发生)

...日志

Error (null)

set question < MYQuestion: 0x17515e20> (entity: MYQuestion; id: 0x17641990 <x-coredata://103ACE29-9CF0-4216-BAF8-A30A04C22B0D/MYQuestion/p12493> ; data: < fault >)

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

1 个答案:

答案 0 :(得分:1)

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

您正在CD_QUEUE访问您的托管对象,因此由Grand Central Dispatch决定此代码将在哪个线程中执行。因此,有可能从“错误”的线程访问这些托管对象 - 而不是他们的context“生活”的线程。

而不是dispatch_async,在performBlock上使用performBlockAndWaitcontext方法之一。它们的目的是确保以安全的方式访问托管对象:

[context performBlock:^{
   //do what you did in dispatch_async block
];

如果您想了解有关核心数据和并发性的更多信息,请阅读详细的(虽然有点过时)Apple的Core Data Concurrency GuideCommon Background Practices by objc.io

对于问题的第二部分:对象为fault并不意味着在获取请求期间出现错误。这意味着对象的属性尚未从持久性存储(如SQLite数据库)加载到内存中。更多相关内容:Faulting and uniquing