2013-01-16 5 views
6

私は1セクションと2行の単純なテーブルビューを持っています。私はNSFetchedResultsControllerを使ってテーブルをCoreDataと同期させています。 CDの行の1つに変更を加えて、テーブルビューセルを更新して移動させます。問題は、NSFetchedResultsChangeUpdateの間にcellForRowAtIndexPath:が呼び出されると間違ったセルが返されることです(これは、セルがまだ移動されていないことを意味します)。間違ったセルは、新しく更新されたデータで更新されます。その後、NSFetchedResultsChangeMoveメッセージが処理され、セルは交換されます(セルの内容は移動呼び出しから更新されません)。その結果、両方のセルは、新しく更新されたCDエンティティからのデータを反映します。テーブルをリロードすると問題が解決されます。私はiOS 6を実行しています。 つまり、インデックス0のセルがエンティティAを表し、インデックス1がエンティティBを表し、エンティティAをA 'に更新すると、2つのセルが逆の順序で更新されます。 0:A '1:A:0:B、1:A'を期待しているときを参照してください。UITableViewCellとNSFetchedResultsControllerの同時移動と更新

答えて

4

私は簡単であるバグを修正このblogpost

を見てみることをお勧めします。ちょうど私が上記のUITableViewの動作に依存しているとconfigureCellへの呼び出しに置き換えます。atIndexPath:reloadRowsAtIndexPathsと:withRowAnimation:方法、自動的に正しいことを行います:

case NSFetchedResultsChangeUpdate: 
    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 
    break; 
+0

それにかかわらず、delete + insertコンボの代わりにmoveRowAtIndexPathを使用すると、私は更新イベントを受け取らない。何が原因である可能性がありますか? – Andy

6
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { 

    UITableView *tableView = self.tableView; 

    switch(type) { 

     case NSFetchedResultsChangeInsert: 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

     case NSFetchedResultsChangeDelete: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

     case NSFetchedResultsChangeUpdate: 
//the wrong cell is updated here 
      [self configureCell:(SyncCell*)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
      break; 

     case NSFetchedResultsChangeMove: 
      [tableView moveRowAtIndexPath:indexPath toIndexPath:newIndexPath]; 
//this code produces errors too 
      //[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      //[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 

溶液である:その更新中に供給された新しいインデックスパスを使用して

[self configureCell:(SyncCell*)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:newIndexPath ? newIndexPath : indexPath]; 

。そして、移動の代わりに削除と挿入を使用してください。私はまだ他の誰かが入力を持っているかどうか知りたいです。

+0

Sweet!これで3日間のように過ごしました... トピックに関する文書:http://developer.apple.com/library/ios/#releasenotes/iPhone/NSFetchedResultsChangeMoveReportedAsNSFetchedResultsChangeUpdate/ –

+0

ああ、面白いです。私は間違って何かをしていなかった知って良いこと:)ありがとう! – Tylerc230

1

唯一の解決策のために働いていました私は:Thomas Worrall's Blog: Reordering rows in a UITableView with Core Data

まず、あなたのオブジェクトの最後の順序をハングするNSManagedObjectの属性を作成する必要があります。

その後
@interface MyEntity : NSManagedObject 

@property (nonatomic, retain) NSNumber * lastOrder; 

@end 

、あなたのViewController.mでプロパティを宣言:方法のtableViewで

@interface ViewController() 

@property (nonatomic) BOOL isReordering; 

@end 

:moveRowAtIndexPath:toIndexPath:

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath 
{ 
    _isReordering = YES; 

    NSMutableArray *arrayNewOrder = [[_fetchedResultsController fetchedObjects] mutableCopy]; 
    MyEntity *myManagedObject = [arrayNewOrder objectAtIndex:fromIndexPath.row]; 
    [arrayNewOrder removeObjectAtIndex:fromIndexPath.row]; 
    [arrayNewOrder insertObject:myManagedObject atIndex:toIndexPath.row]; 

    for (int i=0; i < [arrayNewOrder count]; i++) 
    { 
     myManagedObject = [arrayNewOrder objectAtIndex:i]; 
     myManagedObject.lastOrder = [NSNumber numberWithInt:i]; 
    } 

    _isReordering = NO; 
    NSError *error; 
    BOOL success = [self.fetchController performFetch:&error]; 
    if (!success) 
    { 
     // Handle error 
    } 

    success = [[self managedObjectContext] save:&error]; 
    if (!success) 
    { 
     // Handle error 
    } 
} 
は、一時配列の変化を管理します

トーマスは、コンテキストの取得と保存の実行について説明しました。

フェッチを最初に実行する必要がある理由は完全にわかりませんが、 私はそれを実行したときに巨大なバグを修正しました!

最後のトリックはNSFetchedResultsControllerデリゲートメソッドコントローラ処理している:didChangeObject:atIndexPath:forChangeType:newIndexPath:、特にNSFetchedResultsChangeMove中を:

case NSFetchedResultsChangeMove: 
{ 
    if (!_isReordering) 
    { 
     [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
         withRowAnimation:UITableViewRowAnimationFade]; 
     [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
         withRowAnimation:UITableViewRowAnimationFade]; 
    } 

    break; 
} 

それは私のために働きました!それがあなたを助けることを願っています

+0

FRCでtableview上でmoveRowを使用できず、+ insertを強制的に強制的に使用することはできませんか? – Andy

3

configureCellを呼び出すときは、渡されたオブジェクトに基づいてindexPathをルックアップします。この時点では、indexPathとnewIndexPathの両方が信頼できません。たとえば、

case NSFetchedResultsChangeUpdate: 
    myPath = [controller indexPathForObject:anObject]; 
    if (myPath) { 
     [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:myPath]; 
    } 

    break; 
関連する問題