2012-01-23 24 views
10

Trong Swype xóa (hầu hết các dòng importatnt của phương pháp này):Xóa hàng theo quan điểm của bảng với fetchedResultController

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
if (editingStyle == UITableViewCellEditingStyleDelete) 
    { 
    Table *deleteRow = [self.fetchedResultsController objectAtIndexPath:indexPath]; 
    [self.managedObjectContext deleteObject:deleteRow]; 
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
    } 
} 

Khi xóa hàng tôi nhận được lỗi này:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 2.
The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

Nếu tôi nhận xét dòng cuối cùng của mã ([tableView deleteRowsAtIndexPaths:...]) mọi thứ hoạt động tốt (nhưng tôi phải làm mới xem để xem hàng đó đã bị xóa).

Làm thế nào để làm điều đó đúng cách ..?

EDIT: Xét @Kyr Dunenkoff phản ứng tôi đã thêm:

- (void)controller:(NSFetchedResultsController*)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath*)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath*)newIndexPath 
{ 
    UITableView *tableV = [self tableView]; 
    switch(type) { 
     case NSFetchedResultsChangeDelete: 
      [tableV deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 

- (void)controllerDidChangeContent:(NSFetchedResultsController*)controller 
{ 
    [[self tableView] endUpdates]; 
} 

- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller 
{ 
    [[self tableView] beginUpdates]; 
} 

Tuy nhiên điều này không thay đổi đâm & lỗi. Atm nó chỉ gây ra rằng thêm hàng mới không làm việc nữa.

Trả lời

14

Để thực hiện việc này đúng cách, hãy thực hiện phương thức controller:didChangeObject:, trong đó tạo switch cho các loại thay đổi khác nhau, trong vòng NSFetchedResultsChangeDelete trường hợp chèn [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; của bạn. Bởi vì khi bạn làm việc với nguồn dữ liệu như NSFetchedResultsController, tất cả các thay đổi phải đến từ đó và bảng của bạn chỉ phản ánh chúng. Ngoài ra, bạn có thể triển khai controller:willChangeContentcontroller:didChangeContent, đặt [tableView beginUpdates] vào willChange[tableView endUpdates] vào didChange.

+1

Vui lòng kiểm tra cập nhật trên của tôi, sửa lỗi không hoạt động như tôi đã triển khai (có thể sai ..?). Cảm ơn bạn đã phản hồi! – Vive

+0

Hm. Có gì trong phương thức [tableView: numberOfRowsInSection:] của bạn? Nó sẽ có một cái gì đó giống như 'return [[self.fetchedResultsController fetchedObjects] count];'. –

7

Vấn đề là - như bạn đã phát hiện ra bằng cách bình luận nó ra - dòng cuối cùng của bạn:

[tableView deleteRowsAtIndexPaths:... 

Quả táo bảng Xem Hướng dẫn lập trình cho bạn biết cần phải làm điều đó, nhưng trong thực tế bạn không phải khi sử dụng NSFetchedResultsController. Ý tưởng của NSFetchedResultsController là sẽ chăm sóc cập nhật giao diện người dùng để giữ cho nó được đồng bộ hóa với mô hình để bạn không cần. Do đó, nếu bạn chỉ cần xóa đối tượng khỏi mô hình, bộ điều khiển kết quả đã tìm nạp sẽ xử lý phần còn lại.

[Cập nhật] Rất tiếc, không hoàn toàn chính xác những gì tôi đã nói ở đó. Bộ điều khiển kết quả được tìm nạp sẽ không chỉ "quản lý phần còn lại" mà không cần trợ giúp. Đó là đại biểu sẽ đảm trách phần còn lại, nhưng ai đó cần triển khai ủy quyền của họ. Tôi có thói quen bao gồm lớp trợ giúp CoreDataTablewViewController từ khóa Standford CS193p, đây là lớp con UITableViewController thực hiện tất cả các phương thức được đề xuất trong tài liệu của NSFetchedResultsController. Quan trọng nhất, nó thực hiện các phương thức đại biểu cập nhật khung nhìn bảng khi mô hình thay đổi.

Vì vậy, cách tiếp cận cập nhật của bạn vẫn chính xác: bạn KHÔNG nên đặt deleteRowsAtIndexPaths .. trong mã khiến người dùng xóa chúng, nhưng hãy để bộ điều khiển kết quả tìm nạp lái xe quy trình và triển khai thực hiện nó.

(lấy lớp helper ở đây: http://www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2011-fall, và xem bài giảng 14 để xem làm thế nào để sử dụng nó)

2

câu trả lời Kyr là đúng, nhưng đây là một ví dụ rời rạc như thế nào để xóa một NSManagedObject từ cơ sở dữ liệu của bạn cũng từ từ NSFetchedResultsController:

- (void) deleteObjectFromDBAndTable:(NSIndexPath *)indexPath forTable:(UITableView*)tableView 
{ 
    NSLog(@"Deleting object at row %d", indexPath.row); 

    // Delete the object from the data source 
    NSManagedObject *objToDelete = (NSManagedObject*)[self.fetchedResultsController objectAtIndexPath:indexPath]; 

    // Delete the object from the database 
    [DBHandler deleteObject:objToDelete andSave:YES]; 
} 

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

      [_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 

      break; 
     default: 
      break; 
    } 
} 
2

Bạn cần đảm bảo bạn không tự gọi số [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];. Xóa đối tượng khỏi ngữ cảnh sẽ kích hoạt NSFetchedResultsController để làm mới chính nó VÀ bảng.

Các vấn đề liên quan