2011-08-28 2 views
1

수업을 JSON으로 다운로드하고 파싱 한 다음 코어 데이터에 삽입하는 코드가 있습니다. 그런 다음 UITableView에 표시됩니다. 현재 사용자가 수업을 많이 받으면 연결이 시간 초과되는 경우가 있습니다. 그래서 그들은 (SBJson을 사용하여) 들어 와서 수업을 하나씩 tableview에 추가하려고합니다.코어 데이터 NSObjectInaccessibleException NSManagedObject가 무효화되었습니다.

두 가지의 코드는 기본적으로 동일하지만,있는 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.'" 

내가 차이는이 두 사이에 무엇인지 알고 싶습니다 이 오류의 원인 일 수있는 코드 목록 원래 코드는 각 코어 데이터 객체를 루프에 생성하지만 새 코드는 다운로드 할 때 각 코어 데이터 객체를 만듭니다. listViewArray는 UITableView를 채우는 데 사용되는 배열입니다. 내가이 들어오는대로 JSON을 구문 분석 SBJsonStreamParser 및 SBJsonStreamParserAdapter을 사용하고

.

내가 일하는 구현 (도시하지 않음)해야합니까, 즉 기본적으로 새로운 객체가 수신 될 때마다 아래의 원본 코드 (실행 호출 매회 수신 된 객체의 전체 루프를 통해). 오류의 원인을 알고 싶습니다. 그래도 문제가 해결되지 않습니다.

이 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]; 

을 그리고 여기 파서에서 호출 충돌 코드입니다 :이 모든라고 때문에 루프 코드가 제거 된, : foundObject은 새로운 Json 객체가 다운로드 될 때. cellForRowAtIndexPath :

[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]; 

마지막으로, 여기에 실제있는 tableView에서, 제리스트를 사용할 때 충돌 부분은 덧붙여서 행 == 1이 아니고 어떤 이유로 로우 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"]; 
     } 

답변

3

객체 무효화는 페치를 실행하기 직전에 reset을 managedObjectContext에서 호출 할 때 발생합니다. reset을 호출하면 메모리에있는 오브젝트는 무효화되지만 저장 될 때까지 삭제되지는 않습니다. 유효하지 않은 관리 객체가 배열과 같은 다른 객체에 의해 유지되면 무효화 된 형식으로 저장을 지나서 지속됩니다. 가져 오기를 실행하면 가져 오기가 해당 속성 중 하나에 액세스하려고 시도 할 때 오류를 발생시키는 무효화 된 객체를 반환합니다.

reset은 실행 취소 관리자와 함께 사용될 때 호출됩니다. 이것은 일반적인 것이 아니며 "문맥을 지워야한다"고 부릅니다. 기존 객체를 삭제하려면 명시 적으로 가져 와서 삭제해야합니다.

코드에는 몇 가지 다른 문제가 있습니다. 배열을 만들지 않았더라도 checkRequest 배열에 release을 호출합니다. 이로 인해 배열이 무작위로 사라질 수 있습니다. 마찬가지로 listViewArray은 클래스 속성 인 것처럼 보이지만 접근 자 양식을 사용하지 마십시오. 올바른 보유를 위해 self.listViewArray.

1

대부분의 원인은 파서가 주 스레드에서 실행되지 않고 메인 스레드 파서에서 동일한 ManagedObjectContext을 사용하고 있는지 - 당신은 할 수 없어 - 보장 이상한 행동의 모든 종류의 원인 .

는 새 파서 ManagedObjectContext과 연관을 만들 필요가의 persistentStore와 메인 쓰레드의 ManagedObjectContext

CoreData 프레임 워크는이에 아주 분명하다 - 당신은 스레드 경계를 넘어 ManagedObjectContext 년대를 공유 할 수 없습니다