1

サーバーから製品のリストを取得するアプリを作成しています。次に、それらを Core Data データベースに保存し、GMGridViewを使用して表示します。データソースは NSFetchedResultsController です。サーバーで製品の詳細を変更するときに、iOS アプリを同期して必要な変更を加えたいので、NSFetchedResultsControllerDelegate メソッドを実装します。gridView を適切に更新するにはどうすればよいですか?

- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath
{
        switch(type)
        {
            case NSFetchedResultsChangeInsert:
                [_currentData insertObject:anObject atIndex:newIndexPath.row];
                [_currentData removeObjectAtIndex:indexPath.row];
                [_gmGridView insertObjectAtIndex:newIndexPath.row animated:YES];
                [_gmGridView removeObjectAtIndex:indexPath.row animated:YES];

                [_gmGridView reloadObjectAtIndex:newIndexPath.row animated:YES];
                [_gmGridView reloadObjectAtIndex:indexPath.row animated:YES];

                [_gmGridView reloadData];

                //[self updatePageControl];
                break;

            case NSFetchedResultsChangeDelete:
                [_currentData removeObjectAtIndex:indexPath.row];

                [_gmGridView removeObjectAtIndex:indexPath.row animated:YES];
                //[self updatePageControl];
                [_gmGridView reloadInputViews];
                [_gmGridView reloadData];

                break;

            case NSFetchedResultsChangeUpdate:
                [_gmGridView reloadObjectAtIndex:indexPath.row animated:YES];

                ////////might be irrelevant, but just trying it out
                [_currentData insertObject:anObject atIndex:newIndexPath.row];
                [_currentData removeObjectAtIndex:indexPath.row];
                [_gmGridView insertObjectAtIndex:newIndexPath.row animated:YES];
                [_gmGridView removeObjectAtIndex:indexPath.row animated:YES];

                [_gmGridView reloadObjectAtIndex:newIndexPath.row animated:YES];
                [_gmGridView reloadObjectAtIndex:indexPath.row animated:YES];

                ////////


                [_gmGridView reloadInputViews];
                [_gmGridView reloadData];

                break;

            case NSFetchedResultsChangeMove:
                [_currentData removeObjectAtIndex:indexPath.row];
                [_currentData insertObject:anObject atIndex:newIndexPath.row];
                [_gmGridView removeObjectAtIndex:indexPath.row animated:YES];
                [_gmGridView insertObjectAtIndex:newIndexPath.row animated:YES];

                [_gmGridView reloadInputViews];

                [_gmGridView reloadData];

                break;
        }
}

いくつかの詳細:

_currentData = [[self.fetchedResultsController fetchedObjects]mutableCopy];
//I did this because previously I wasn't using a fetchedResultsController but a NSMutableArray instead. I know that it's inefficient (because I have 2 models) but this is the simplest implementation I want to do now. 

同じローカル URL から割り当てられた同じ UIManagedDocument を変更して、別のクラスで CoreData を変更します。

ただし、次の 2 つの重要な問題があります。

  • データベース内のアイテムは更新されますが (製品名や価格の変更など)、変更が UI に反映されません。つまり、GMGridViewCell を正しく再読み込みできません。(上記のリロードに関連するコードに注意してください)
  • ほとんどの場合、サーバーで更新した製品はデータベースで複製されますが、このようなエラーを防ぐメカニズムはあります。(商品を作成する前に、まず一意の識別子を使用して既存の商品を検索します。既存の商品があれば、その詳細を変更するだけです)。コードは次のとおりです。

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Product"];        

request.predicate = [NSPredicate predicateWithFormat:@"product_id = %@", [imonggoInfo   objectForKey:PRODUCT_ID]];    

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];    

request.sortDescriptors = [NSArray 

arrayWithObject:sortDescriptor];  NSError *error = nil;  

NSArray *matches = [context executeFetchRequest:request error:&error];

if (!matches | ([matches count] > 1)){
    //handle error
}else if ([matches count] == 0){
    //make a new product
}else{
    //return existing
    item = [matches lastObject];
}
4

1 に答える 1

1

私は耳を傾ける必要NSManagedObjectContextDidSaveNotificationがあり、バックグラウンドスレッドで変更されたコンテキストとメインスレッドのコンテキストの変更をマージする必要があることがわかりました。私はこの質問で選ばれた答えからアイデアを得ました

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:nil];

//次に、コンテキストの変更をマージする必要があります

- (void)contextDidSave:(NSNotification*)notification{
    NSLog(@"contextDidSave Notification fired.");
    SEL selector = @selector(mergeChangesFromContextDidSaveNotification:);
    [self.itemDatabase.managedObjectContext performSelectorOnMainThread:selector withObject:notification waitUntilDone:NO]; 
}
于 2012-10-15T13:31:21.560 に答える