Iphone 核心数据NSObjectInaccessibleException NSManagedObject已无效

Iphone 核心数据NSObjectInaccessibleException NSManagedObject已无效,iphone,ios,json,core-data,sbjson,Iphone,Ios,Json,Core Data,Sbjson,我有一些代码将课程下载为JSON,解析它们,并将它们放入核心数据。然后,它们将显示在UITableView中。目前,当用户有很多课程时,连接有时会超时。因此,我试图在课程进入时解析它们(使用SBJson),并将它们一次一个地添加到tableview中 这两个版本的代码基本相同,但是新代码在tableView的东西出现时会导致崩溃,并出现错误 "Terminating app due to uncaught exception 'NSObjectInaccessibleException', r

我有一些代码将课程下载为JSON,解析它们,并将它们放入核心数据。然后,它们将显示在UITableView中。目前,当用户有很多课程时,连接有时会超时。因此,我试图在课程进入时解析它们(使用SBJson),并将它们一次一个地添加到tableview中

这两个版本的代码基本相同,但是新代码在tableView的东西出现时会导致崩溃,并出现错误

"Terminating app due to uncaught exception 
'NSObjectInaccessibleException', reason: 'The NSManagedObject with ID:0x5ad0570 <x-coredata://A21AC71F-175B-423D-BF7D-C67BEE094460/Lessons/p18> has been invalidated.'"
最后,这里是使用第二个列表时崩溃的实际部分,在tableView:CellForRowatineXpath中:顺便说一句,它在row==1而不是row==0时崩溃。出于某种原因,第0行是可以的。。。当然,它从来没有机会加载其他行

        titleLabel.text = [[[listViewArray objectAtIndex:indexPath.row] valueForKey:@"lesson"] valueForKey:@"mTitle"]; // CRASH!
        labelCards.text = [NSString stringWithFormat:@"%@ Cards", [[[listViewArray objectAtIndex:indexPath.row]  valueForKey:@"lesson"] valueForKey:@"cards_count"]];

        if([[listViewArray objectAtIndex:indexPath.row] objectForKey:@"userImageObj"] == nil){
            mImageView.backgroundColor = [UIColor grayColor];
            if ([[listViewArray objectAtIndex:indexPath.row] objectForKey:@"isThreadLaunched"] == nil) {
                [NSThread detachNewThreadSelector:@selector(loadImagesInBackground:) toTarget:self withObject:[NSNumber numberWithInt:indexPath.row]];
                [[listViewArray objectAtIndex:indexPath.row] setObject:@"Yes" forKey:@"isThreadLaunched"];
            }
        }else {
            mImageView.image = [[listViewArray objectAtIndex:indexPath.row] objectForKey:@"userImageObj"];
        }

最可能的原因是解析器没有在主线程上运行,并且您在主线程上使用相同的ManagedObjectContext,而解析器(您不能这样做)保证会导致各种奇怪的行为

您需要在解析器中创建一个新的ManagedObjectContext,并将其与主线程的ManagedObjectContext的persistentStore相关联


CoreData框架在这一点上非常清楚—您不能跨线程边界共享ManagedObjectContext

最可能的原因是解析器没有在主线程上运行,并且您在主线程和解析器之间使用相同的ManagedObjectContext—您不能这样做—保证会引起各种奇怪的问题行为

您需要在解析器中创建一个新的ManagedObjectContext,并将其与主线程的ManagedObjectContext的persistentStore相关联


CoreData框架在这一点上非常清楚-您不能跨线程边界共享ManagedObjectContext的对象无效性

在运行获取之前,在ManagedObjectContext上调用
重置
时,最有可能发生对象无效。调用
reset
会使内存中的对象无效,但在保存之前不会删除它们。如果无效的托管对象由另一个对象(如数组)保留,则该对象将以无效形式保存。运行fetch时,fetch将返回无效对象,当您尝试访问这些对象的一个属性时,这些对象会导致错误

reset
用于撤销管理器时调用。它不是一个通用的“擦除上下文”调用。如果要删除现有对象,则需要获取它们并显式删除它们


您的代码还存在一些其他问题。您可以在
checkRequest
数组上调用
release
,即使您没有创建它。这可能会导致阵列随机消失。类似地,
listViewArray
似乎是一个类属性,但您从不使用访问器表单,例如
self.listViewArray
来确保正确的保留

在运行提取之前,在managedObjectContext上调用
reset
时,最有可能发生对象无效。调用
reset
会使内存中的对象无效,但在保存之前不会删除它们。如果无效的托管对象由另一个对象(如数组)保留,则该对象将以无效形式保存。运行fetch时,fetch将返回无效对象,当您尝试访问这些对象的一个属性时,这些对象会导致错误

reset
用于撤销管理器时调用。它不是一个通用的“擦除上下文”调用。如果要删除现有对象,则需要获取它们并显式删除它们

您的代码还存在一些其他问题。您可以在
checkRequest
数组上调用
release
,即使您没有创建它。这可能会导致阵列随机消失。类似地,
listViewArray
似乎是一个类属性,但您从不使用访问器表单,例如
self.listViewArray
来确保正确的保留

    [jsonStreamedData addObject:dict];
    if (!listViewArray)
        listViewArray = [[NSMutableArray alloc] init];

    MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
    NSError *error = nil;
    [appDelegate.managedObjectContext reset];

    NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext;

    NSFetchRequest *checkRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *lessonEntity = [NSEntityDescription entityForName:@"Lessons" inManagedObjectContext:managedObjectContext];
    [checkRequest setEntity:lessonEntity];
    NSPredicate *langPredicate = [NSPredicate predicateWithFormat:@"(language = %@)", appDelegate.currentLanguage];
    NSPredicate *userPredicate = [NSPredicate predicateWithFormat:@"(username = %@)", appDelegate.userName];
    NSPredicate *idPredicate = [NSPredicate predicateWithFormat:@"(content_Id = %@)", [dict valueForKey:@"id"]];
    [checkRequest setPredicate:[NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:langPredicate, userPredicate, idPredicate, nil]]];

    NSArray *checkResults = [managedObjectContext executeFetchRequest:checkRequest error:&error];
    [checkRequest release];

    NSMutableDictionary *tempDict = [[NSMutableDictionary alloc] init];

    if ([checkResults count]) {
        Lessons *lessonObj = [checkResults objectAtIndex:0];
        lessonObj.cards_count = [dict valueForKey:@"cards_count"];
        lessonObj.mTitle = [dict  valueForKey:@"title"];
        lessonObj.sound_Url = [dict valueForKey:@"audio_url"];
        lessonObj.mId = [NSNumber numberWithInt:jsonStreamedData.count - 1]; // This should be equivalent to i from the loop in the first code
        [tempDict setValue:lessonObj forKey:@"lesson"];
        [tempDict setValue: [dict objectForKey:@"image_url"] forKey:@"image_url"];
        [listViewArray addObject:tempDict];

    }
    else {

        Lessons *newLesson = (Lessons *)[NSEntityDescription insertNewObjectForEntityForName:@"Lessons" inManagedObjectContext:appDelegate.managedObjectContext];
        newLesson.cards_count = [dict valueForKey:@"cards_count"];
        newLesson.mTitle = [dict valueForKey:@"title"];
        newLesson.sound_Url = [dict valueForKey:@"audio_url"];
        newLesson.content_Id = [dict valueForKey:@"id"];
        newLesson.username = appDelegate.userName;
        newLesson.language = appDelegate.currentLanguage;
        newLesson.mId = [NSNumber numberWithInt:jsonStreamedData.count - 1];
        [tempDict setValue:newLesson forKey:@"lesson"];
        [tempDict setValue: [dict  objectForKey:@"image_url"] forKey:@"image_url"]; 
        [listViewArray addObject:tempDict];

    }

    [tempDict release];
    tempDict = nil;

    if (![appDelegate.managedObjectContext save:&error]) {
        ALog(@"Core Data Error - %@", [error localizedDescription]);
    }   

    //  NSMutableArray *tempArray = [NSMutableArray arrayWithArray:listViewArray];
    //  [listViewArray removeAllObjects];
    //  [listViewArray addObjectsFromArray:[[tempArray reverseObjectEnumerator] allObjects]];
    //  tempArray = nil;
//[self getListsLocally];
[mListsTableView reloadData];
        titleLabel.text = [[[listViewArray objectAtIndex:indexPath.row] valueForKey:@"lesson"] valueForKey:@"mTitle"]; // CRASH!
        labelCards.text = [NSString stringWithFormat:@"%@ Cards", [[[listViewArray objectAtIndex:indexPath.row]  valueForKey:@"lesson"] valueForKey:@"cards_count"]];

        if([[listViewArray objectAtIndex:indexPath.row] objectForKey:@"userImageObj"] == nil){
            mImageView.backgroundColor = [UIColor grayColor];
            if ([[listViewArray objectAtIndex:indexPath.row] objectForKey:@"isThreadLaunched"] == nil) {
                [NSThread detachNewThreadSelector:@selector(loadImagesInBackground:) toTarget:self withObject:[NSNumber numberWithInt:indexPath.row]];
                [[listViewArray objectAtIndex:indexPath.row] setObject:@"Yes" forKey:@"isThreadLaunched"];
            }
        }else {
            mImageView.image = [[listViewArray objectAtIndex:indexPath.row] objectForKey:@"userImageObj"];
        }