8

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ó.

enter image description here

Để đạ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:

enter image description here

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"); 
    } 
} 
+0

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. –

+0

Bạn sẽ tải lại bảng như thế nào? –

+0

Đăng mã được gọi khi dấu kiểm được khai thác. – jcm

Trả lời

6

Vâng, tôi nghĩ tôi có thể đã bẻ khóa. Như thường là trường hợp, tước nó xuống và đọc chỉ là một vài ý kiến ​​chỉ cho tôi đi đúng hướng.

Khi tôi đến bộ điều khiển phương thức đại biểuDidChangeObject, tôi cố gắng chèn một hàng tại indexPath được cung cấp (cho mục 'đã chọn'). Ngoại trừ khi chèn vào phần bổ sung của tôi, indexPath này không nhận thức được thực tế rằng có một loạt các phần khác trước đó. Vì vậy, nó nhận được phần 0 và cố gắng chèn vào đó. Thay vào đó, nếu indexPath đến từ FRC thứ hai, tôi nên tăng số phần bằng số lượng các phần trong bảng FRC đầu tiên. Vì vậy, tôi thay thế:

- (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; 

với

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

UITableView *tableView = self.tableView; 

switch(type) { 
    case NSFetchedResultsChangeInsert: 

     if ([controller.sectionNameKeyPath isEqualToString:@"department"]) { 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
     } 
     else { 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:newIndexPath.row inSection:firstFRC.sections.count]] withRowAnimation:UITableViewRowAnimationFade];   } 
     break; 

tôi sẽ cần phải làm điều này cho mỗi chèn, xóa, cập nhật vv Tôi sẽ đánh dấu đây là câu trả lời sau khi tôi đã xác nhận điều này và để cho phép thời gian cho ý kiến ​​khác.

+0

Xác nhận làm việc sau thay đổi này. –

+0

Bạn cũng có thể kiểm tra xem ([controller isEqualTo: self.firstFetchedResultsController]) – 3lvis

0

Các lỗi bạn đang nhìn thấy có nghĩa là UITableView load lại của bạn thân trước khi CẢ NSFetchedResultsController của bạn s làm. Các mã bạn đăng có lẽ là chính xác. Tôi nghi ngờ rằng sự cố là một trong các phương pháp NSFetchedResultsControllerDelegate.

+0

Bạn có nghĩa là controllerWillChangeContent, vv? Những thứ này tôi đã bán buôn từ bản demo của Apple. –

+0

Bạn nghi ngờ chính xác, cảm ơn nhiều! –

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