Sau nhiều ngày nghiên cứu và tái mã hóa, tôi khá là bối rối. Mục tiêu của tôi là để có được một ứng dụng thử nghiệm chạy với một tableview đơn dân cư từ hai fetchedResultControllers riêng biệt.TableView với hai trường hợp của NSFetchedResultsController
Tôi có một loạt các mặt hàng trong danh sách mua sắm, mỗi mặt hàng có một bộ phận và một cờ 'được thu thập boolean'. Các mục không được thu thập sẽ được liệt kê theo bộ phận, theo sau là một phần có chứa tất cả các mục được thu thập (bất kể bộ phận). Khi người dùng kiểm tra các mục không bị thu thập, họ sẽ chuyển xuống phần 'đã thu thập'. Nếu anh ta không kiểm tra một mục được thu thập, nó sẽ chuyển trở lại bộ phận chính xác của nó.
Để đạt được phần đầu tiên (mục uncollected), tôi thiết lập một fetchedResultsController đơn giản mà lấy về tất cả các mục trong đó thu thập = NO, và sectioned kết quả theo bộ phận:
- (NSFetchedResultsController *)firstFRC {
// Set up the fetched results controller if needed.
if (firstFRC == nil) {
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// fetch items
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
// only if uncollected
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(collected = NO)"];
[fetchRequest setPredicate:predicate];
// sort by name
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
// fetch results, sectioned by department
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"department" cacheName:nil];
aFetchedResultsController.delegate = self;
self.firstFRC = aFetchedResultsController;
}
return firstFRC;
}
tôi đặt số lượng hàng, phần và tiêu đề phần như sau:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return firstFRC.sections.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[firstFRC.sections objectAtIndex:section] numberOfObjects];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[[firstFRC sections] objectAtIndex:section] name];
}
Tôi cũng sử dụng bộ điều khiển boilerplateWillChangeContent, didCha ngeObject và controllerDidChangeContent để thêm/xóa các ô khi thay đổi của FRC.
Để ngắn gọn, tôi sẽ không bao gồm mã để hiển thị ô, nhưng về cơ bản tôi kéo mục chính xác dựa trên đường dẫn chỉ mục của ô, đặt văn bản/phụ đề của ô và đính kèm một trong hai hình ảnh dấu kiểm, tùy thuộc vào mục được thu thập hay không. Tôi cũng dây lên hình ảnh này (mà là trên một nút) để chuyển đổi từ kiểm tra để bỏ chọn khi nó được xúc động, và cập nhật các mục cho phù hợp.
Phần này tất cả đều hoạt động tốt. Tôi có thể xem danh sách các mục của tôi theo bộ phận, và khi tôi đánh dấu một mục như được thu thập, tôi thấy nó sẽ bị loại khỏi danh sách như mong đợi.
Bây giờ tôi đã cố gắng thêm phần dưới cùng, chứa tất cả các mục đã thu thập (trong một phần). Trước tiên, tôi thiết lập một fetchedResultsConroller thứ hai, lần này chỉ lấy các mục không bị thu thập và không có phân đoạn. Tôi cũng đã phải cập nhật những điều sau đây:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections - add one for 'collected' section
return firstFRC.sections.count + 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section
if (section < firstFRC.sections.count) {
return [[firstFRC.sections objectAtIndex:section] numberOfObjects];
}
else {
return secondFRC.fetchedObjects.count;
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (section < firstFRC.sections.count) {
return [[[firstFRC sections] objectAtIndex:section] name];
}
else{
return @"Collected";
}
}
sau đó tôi cập nhật các cellForRowAtIndexPath trong một thời trang tương tự, do đó mục Tôi lấy xuất phát từ quyền FRC:
Item *item;
if (indexPath.section < firstFRC.sections.count) {
item = [firstFRC objectAtIndexPath:indexPath];
}
else {
item = [secondFRC objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
}
[[cell textLabel] setText:[item name]];
…rest of cell configuration
này hoạt động tuyệt vời khi tôi khởi động . Hiển thị tableview chính xác như mong đợi:
Vấn đề (cuối cùng)
The (đầu tiên) vấn đề đến khi tôi chọn dấu kiểm cho một mục uncollected. Tôi hy vọng mục sẽ bị xóa khỏi bộ phận được liệt kê dưới đây và chuyển đến phần 'đã thu thập'.Thay vào đó, tôi nhận được:
CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)
Nếu tôi cố gắng điều ngược lại, sau đó tôi nhận được một lỗi khác nhau:
* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
tôi nghi ngờ rằng trong cả hai trường hợp có một vấn đề với tính nhất quán với số lượng phần/các hàng trong FRC và tableview khi một mục chuyển từ FRC này sang FRC khác. Mặc dù lỗi thứ hai đó khiến tôi nghĩ rằng có thể có một vấn đề đơn giản hơn liên quan đến việc truy xuất các mục của tôi.
Mọi hướng hoặc ý tưởng sẽ được đánh giá cao. Tôi có thể cung cấp thêm mã của mình nếu nó sẽ giúp ích và cũng đã tạo một ứng dụng thử nghiệm nhỏ với một chế độ xem duy nhất để chứng minh sự cố. Tôi có thể tải nó lên nếu cần thiết, nhưng chủ yếu là tôi muốn kiểm tra vấn đề trong một sandbox nhỏ.
Update - mã bổ sung yêu cầu
Theo yêu cầu, đây là những gì sẽ xảy ra khi một đánh dấu được xúc động:
- (void)checkButtonTapped:(id)sender event:(id)event
{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint: currentTouchPosition];
if (indexPath != nil)
{
[self tableView: self.tableView accessoryButtonTappedForRowWithIndexPath: indexPath];
}
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
Item *item;
if (indexPath.section < firstFRC.sections.count) {
item = [firstFRC objectAtIndexPath:indexPath];
}
else {
item = [secondFRC objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]];
}
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
UIButton *button = (UIButton *)cell.accessoryView;
if (![item collected]) {
[item setCollected:YES];
[button setBackgroundImage:[UIImage imageNamed:@"checked.png"] forState:UIControlStateNormal];
}
else if ([item collected]){
[item setCollected:NO];
[button setBackgroundImage:[UIImage imageNamed:@"unchecked.png"] forState:UIControlStateNormal];
}
NSError *error = nil;
if (![item.managedObjectContext save:&error]) {
NSLog(@"Error saving collected items");
}
}
Lưu ý: tên bộ phận hơi tắt trong ảnh chụp màn hình. Tôi quên sử dụng dept làm bộ mô tả sắp xếp đầu tiên. –
Bạn sẽ tải lại bảng như thế nào? –
Đăng mã được gọi khi dấu kiểm được khai thác. – jcm