1

レッスンをJSONとしてダウンロードし、解析してコアデータに入れるコードがいくつかあります。その後、UITableViewに表示されます。現在、ユーザーが多くのレッスンを受けていると、接続がタイムアウトすることがあります。そこで、(SBJsonを使用して)入ってくるレッスンを解析し、一度に1つずつテーブルビューに追加しようとしています。

2つのコードは基本的に同じですが、新しいコードを使用すると、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.'"

このエラーの原因となっている可能性のあるこれら2つのコードリストの違いを知りたいのですが。元のコードはループ内で各コアデータオブジェクトを作成しますが、新しいコードはダウンロード時に各コアデータオブジェクトを作成します。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];

最後に、tableView:cellForRowAtIndexPathの2番目のリストを使用するとクラッシュする実際の部分は次のとおりです。ちなみに、行==0ではなく行==1のときにクラッシュします。何らかの理由で行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"];
        }
4

2 に答える 2

3

オブジェクトの無効化resetは、フェッチを実行する直前にmanagedObjectContextを呼び出すときに発生する可能性があります。呼び出すresetと、メモリ内のオブジェクトは無効になりますが、保存するまでオブジェクトは削除されません。無効化された管理対象オブジェクトがアレイなどの別のオブジェクトによって保持されている場合、無効化された形式で保存された後も保持されます。フェッチを実行すると、フェッチは無効化されたオブジェクトを返します。これにより、属性の1つにアクセスしようとするとエラーが発生します。

reset元にしいマネージャーで使用するときに呼び出されることを意図しています。これは、一般的な「コンテキストのワイプ」呼び出しではありません。既存のオブジェクトを削除する場合は、それらをフェッチして明示的に削除する必要があります。

コードには他にもいくつか問題があります。配列を作成していなくてもrelease、配列を呼び出します。checkRequestこれにより、アレイがランダムに消える可能性があります。同様に、listViewArrayはクラスプロパティのように見えますが、self.listViewArray適切な保持を確保するためなど、アクセサフォームを使用することはありません。

于 2011-08-29T20:31:53.957 に答える
1

最も可能性の高い原因は、パーサーがメインスレッドで実行されておらず、メインスレッドとパーサーで同じManagedObjectContextを使用していることです(これはできません)。あらゆる種類の奇妙な動作が発生することが保証されています。

パーサーで新しいManagedObjectContextを作成し、それをメインスレッドのManagedObjectContextのpersistentStoreに関連付ける必要があります

CoreDataフレームワークはこれについて非常に明確です-スレッドの境界を越えてManagedObjectContextを共有することはできません

于 2011-08-28T22:48:12.720 に答える