iphone之核心数据 NSObjectInaccessibleException NSManagedObject 已失效

jackei 阅读:88 2025-06-02 22:19:02 评论:0

我有一些代码可以将类(class)下载为 JSON、解析它们并将它们放入核心数据中。然后将它们显示在 UITableView 中。目前,当用户有很多类(class)时,连接有时会超时。因此,我试图在类(class)进入时解析类(class)(使用 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.'" 

我想知道这两个可能导致此错误的代码 list 之间的区别是什么。原始代码在循环中创建每个核心数据对象,但新代码在下载每个核心数据对象时创建它。 listViewArray 是用于填充 UITableView 的数组。

我正在使用 SBJsonStreamParser 和 SBJsonStreamParserAdapter 来解析 Json。

我确实有一个有效的实现(未显示),它基本上每次接收到一个新对象时都会调用下面的原始代码(每次都通过接收到的对象的完整循环运行)。不过,我想知道是什么导致了错误,而不仅仅是让某些东西正常工作。

这是原始的非流式代码,在 connectionDidFinishLoading 中调用:
    NSMutableArray *tempListArray = [[NSMutableArray alloc] initWithArray:jsonStreamedData]; 
 
    if (listViewArray) 
        [listViewArray release]; 
    listViewArray = [[NSMutableArray alloc] init]; 
 
    if(![tempListArray count]){ 
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Message" message:@"No active lessons " delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; 
        [alertView show]; 
        [alertView release]; 
    } 
    else { 
        MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate]; 
        NSError *error = nil; 
        [appDelegate.managedObjectContext reset]; 
 
        NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext; 
        for (int i = 0; i < [tempListArray count]; i++) { 
 
            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 = %@)", [[tempListArray objectAtIndex:i] 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 = [[tempListArray objectAtIndex:i] valueForKey:@"cards_count"]; 
                lessonObj.mTitle = [[tempListArray objectAtIndex:i] valueForKey:@"title"]; 
                lessonObj.sound_Url = [[tempListArray objectAtIndex:i] valueForKey:@"audio_url"]; 
                lessonObj.mId = [NSNumber numberWithInt:i]; 
                [tempDict setValue:lessonObj forKey:@"lesson"]; 
                [tempDict setValue: [[tempListArray objectAtIndex:i]  objectForKey:@"image_url"] forKey:@"image_url"]; 
                [listViewArray addObject:tempDict]; 
 
            } 
            else { 
 
                Lessons *newLesson = (Lessons *)[NSEntityDescription insertNewObjectForEntityForName:@"Lessons" inManagedObjectContext:appDelegate.managedObjectContext]; 
                newLesson.cards_count = [[tempListArray objectAtIndex:i] valueForKey:@"cards_count"]; 
                newLesson.mTitle = [[tempListArray objectAtIndex:i] valueForKey:@"title"]; 
                newLesson.sound_Url = [[tempListArray objectAtIndex:i] valueForKey:@"audio_url"]; 
                newLesson.content_Id = [[tempListArray objectAtIndex:i] valueForKey:@"id"]; 
                newLesson.username = appDelegate.userName; 
                newLesson.language = appDelegate.currentLanguage; 
                newLesson.mId = [NSNumber numberWithInt:i]; 
                [tempDict setValue:newLesson forKey:@"lesson"]; 
                [tempDict setValue: [[tempListArray objectAtIndex:i]  objectForKey:@"image_url"] forKey:@"image_url"];  
                [listViewArray addObject:tempDict]; 
 
            } 
            [tempDict release]; 
            tempDict = nil; 
        } 
 
 
        if (![appDelegate.managedObjectContext save:&error]) { 
            NSLog(@"Core Data Error - %@", [error localizedDescription]); 
 
        }    
 
        //      NSMutableArray *tempArray = [NSMutableArray arrayWithArray:listViewArray]; 
        //      [listViewArray removeAllObjects]; 
        //      [listViewArray addObjectsFromArray:[[tempArray reverseObjectEnumerator] allObjects]]; 
        //      tempArray = nil; 
    } 
    [tempListArray release]; 
} 
[mListsTableView reloadData]; 

这是崩溃的代码,在 parser:foundObject 中调用:循环代码已被删除,因为每次下载新的 Json 对象时都会调用它。
    [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]; 

最后,这是使用第二个 list 时崩溃的实际部分,在 tableView:cellForRowAtIndexPath: 顺便说一句,当 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"]; 
        } 

请您参考如下方法:

当您调用 reset 时,最有可能发生对象失效。在运行 fetch 之前在 managedObjectContext 上。调用reset使内存中的对象无效,但在保存之前不会删除它们。如果一个无效的托管对象被另一个对象(例如数组)保留,那么它将在保存后以无效的形式持续存在。当您运行提取时,提取返回无效对象,当您尝试访问它们的属性之一时会导致错误
reset与撤消管理器一起使用时会被调用。它不是通用的“删除上下文”调用。如果要删除现有对象,则需要获取它们并显式删除它们。

您的代码还有其他一些问题。您调用releasecheckRequest即使您没有创建数组。这可能会导致数组随机消失。 listViewArray 也是如此似乎是一个类属性,但您从不使用访问器形式,例如self.listViewArray以确保适当的保留。


标签:Exception
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号