2009-08-25 25 views
10

Các tài liệu cho NSFetchedResultsControllerDelegate cung cấp mẫu mã sau đâyHành vi NSFetchedResultsControllerDelegate 'ChangeUpdate' có bị hỏng không?

- (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: 
      [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
      break; 

     case NSFetchedResultsChangeMove: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      [tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 

    } 

} 

Khi tôi tạo ra một NSManagedObject mới, NSFetchedResultsChangeInsert cháy (tuyệt vời!). Khi tôi thay đổi giá trị của một thuộc tính (được sử dụng cho tiêu đề của ô), các vụ cháy NSFetchedResultsChangeUpdate. Thật không may, tiêu đề mới không tự động hiển thị trừ khi tôi tải lại bảng, phần hoặc hàng. Thật vậy, nếu tên mới khiến cho tập kết quả sắp xếp khác nhau, thì NSFetchedResultsChangeMove cháy và tất cả là tốt kể từ khi mã được cung cấp tải lại toàn bộ phần.

UITableView có một phương pháp reloadRowsAtIndexPaths: withRowAnimation vì vậy tôi cố gắng sử dụng này theo những NSFetchedResultsChangeUpdate khối mã. Nó thực sự làm việc ... nhưng tài liệu cho phương pháp cụ thể này đọc như thể tôi không cần nó (chú ý dòng cuối cùng):

Reloading một hàng gây ra quan điểm bảng để hỏi nguồn dữ liệu của nó cho một ô mới cho hàng đó. Bảng hoạt ảnh mà ô mới trong đó làm hoạt hình hàng cũ. Gọi phương thức này nếu bạn muốn thông báo cho người dùng rằng giá trị của ô đang thay đổi. Tuy nhiên, nếu thông báo cho người dùng không phải là quan trọng - tức là bạn chỉ muốn thay đổi giá trị mà ô là hiển thị — bạn có thể nhận được một hàng cụ thể và đặt giá trị mới.

Và vâng, nếu tôi đăng nhập gì đang xảy ra, khi

[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 

được gọi trên một NSFetchedResultsChangeUpdate, nó có thể lấy lại 'tên' giá trị mới nhất và đặt nó trong textLabel của tế bào . Tên không chỉ hiển thị trong ô trừ khi tôi tải lại. Ngay cả khi tôi chỉ cần nhấp vào ô mà tên hiển thị. Lưu ý rằng để tạo lại hành vi này, bạn phải tạo một đối tượng được quản lý mới và sau đó đặt cho nó một tên khiến nó sắp xếp FIRST trong NSFetchedResultsController. Bằng cách đó, NSFetchedResultsChangeMove không kích hoạt (hoạt động vì nó tải lại phần này).

Tôi có thiếu điều gì đó hoặc hành vi mong đợi này không? 'Thảo luận' cho reloadRowsAtIndexPaths dẫn tôi tin rằng tôi có thể chỉ cần đặt textLabel của ô mà không cần tải lại hàng, phần hoặc bảng.

+0

Điều này cần được làm rking. Tôi đang làm điều tương tự. Đối với các thay đổi đối với các thuộc tính, khi lưu: được gọi, thông báo MOC sẽ xuất hiện. NSFetchedResultsController thấy sự thay đổi và gọi phương thức configureCell: atIndexPath của tôi. Ở đó tôi lấy các giá trị và điền vào ô, và ô được cập nhật ngay lập tức. Đăng mã configureCell của bạn. –

Trả lời

3

Bạn nên gọi [cell setNeedsLayout] hoặc/và [cell setNeedsDisplay] để làm cho ô được làm mới, tùy thuộc vào việc triển khai ô của bạn.

Nếu bạn soạn ô của các bản xem trước như chúng tôi thường làm, bạn dựa vào - layoutSubviews, vì vậy bạn nên gọi [cell setNeedsLayout].

Nếu bạn vẽ ô trực tiếp bằng – drawRect:, bạn nên gọi [cell setNeedsDisplay].

Nếu bạn sử dụng cả bố cục và bản vẽ, bạn nên gọi cả hai.

1

Mặc dù đúng là bạn không cần phải tải lại ô để có thay đổi diễn ra, bạn phải nhớ rằng chế độ xem bộ nhớ cache trên iPhone càng nhiều càng tốt. Khi bạn đã cấu hình xong ô của mình, bạn cần gọi setNeedsDisplay trên ô để kích hoạt vẽ lại.

+0

Tại thời điểm này - cách tốt nhất để lấy ô trên màn hình là gì? tableview: cellForRowAtIndexPath: tạo một ô mới trong khi tôi muốn lấy tham chiếu đến ô trên màn hình ... phải không? –

+0

Thông thường, không cần thiết, đối với bất kỳ ô nào bạn đang định cấu hình, bạn có thể gọi setNeedsDisplay. Nếu đó là một ô mới, nó không có bộ đệm, vì vậy đừng lo lắng, nếu bạn định cấu hình lại, nó sẽ vẽ lại. Tuy nhiên, nếu bạn thực sự muốn biết màn hình nào hiển thị, hãy xem phản hồi của tôi về: http://stackoverflow.com/questions/996515/getting-visible-cell-from-uitableview-pagingenabled/1566432#1566432 –

1

Mặc dù nó không được quy định rõ ràng, bạn đã thực sự có để đảm bảo rằng bạn bao gồm các phương pháp đại biểu cho controllerWillChangeContent: và controllerDidChangeContent:

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

- (void)controllerDidChangeContent:(BSFetchedResultsController *)controller { 
    @try { 
     [self.tableView endUpdates]; 
    } 
    @catch (NSException * e) { 
     NSLog(@"caught exception: %@: %@", [e name], [e description]); 
    } 
    @finally { } 
} 

Các NSFRC có thể bắn tắt nhiều điều khiển: didChangeObject: atIndexPath: forChangeType: newIndexPath: phương thức trong bất kỳ thay đổi nào, vì vậy đừng mong đợi hàng của bảng sẽ cập nhật ngay sau mỗi một trong số đó. Chúng sẽ chỉ cập nhật sau khi bạn gọi endUpdates trên bảng.

0

Gọi UI cập nhật Logic trong CHỦ Chủ đề giải quyết vấn đề của tôi (cả [cell setNeedsLayout] & [cell setNeedsDisplay] không hoạt động đối với tôi):

... 
case NSFetchedResultsChangeUpdate: 
    dispatch_async(dispatch_get_main_queue(), { 
     [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
    }); 
    break; 
... 

Hơn thế nữa (không phải về vấn đề này, nhưng sẽ hữu ích), tốt hơn bạn nên chọn sử dụng newIndexPath nếu có sẵn:

... 
case NSFetchedResultsChangeUpdate: 
    dispatch_async(dispatch_get_main_queue(), { 
     NSIndexPath * targetIndexPath = (newIndexPath ?: indexPath) 
     [self configureCell:[tableView cellForRowAtIndexPath:targetIndexPath] 
       atIndexPath:targetIndexPath]; 
    }); 
    break; 
... 
+1

những các sự kiện đã có trên thread chính, những gì bạn đang làm là shunting đến vòng lặp sự kiện tiếp theo, mặc dù GCD không phải là 100% tốt ở đó, thực hiện sau khi chậm trễ là đáng tin cậy hơn. – malhal

+0

@malhal điểm tốt. – Kjuly

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