25

Điều tôi muốn làm là khá đơn giản. Trong UITableViewController của tôi, tôi muốn tải dữ liệu từ nhiều NSFetchedResultControllers (Tôi có nhiều thực thể trong mô hình dữ liệu của tôi) và đưa dữ liệu từ mỗi một thành một phần khác nhau trong khung nhìn bảng. Vì vậy, ví dụ, tất cả các mục đã tìm nạp từ NSFetchedResultController đầu tiên sẽ đi vào phần 0 trong UITableView, các mục được tìm nạp từ mục khác đi vào phần 1, v.v.Dữ liệu cốt lõi: UITableView với nhiều NSFetchedResultControllers

Dự án mẫu dữ liệu cốt lõi không thể hiện cách làm cái này. Mọi thứ (chủ yếu là các đường dẫn chỉ mục) được mã hóa mà không tính đến các phần (không có phần nào trong mẫu mặc định) và mọi thứ được lấy từ một NSFetchedResultController. Có bất kỳ dự án hoặc tài liệu ví dụ nào chứng tỏ việc này không?

Cảm ơn

Trả lời

24

Giả sử một lúc sau trong tiêu đề của bạn (mã dưới đây sẽ hơi luộm thuộm, lời xin lỗi của tôi):

NSFetchedResultsController *fetchedResultsController1; // first section data 
NSFetchedResultsController *fetchedResultsController2; // second section data 

Hãy bàn biết bạn muốn có 2 phần:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return 2; // you wanted 2 sections 
} 

Give it các đề mục:

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { 
    return [NSArray arrayWithObjects:@"First section title", @"Second section title", nil]; 
} 

Hãy bàn biết bao nhiêu hàng có mỗi phần:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    if (section == 0) { 
     return [[fetchedResultsController1 fetchedObjects] count]; 
    } else if (section == 1) { 
     return [[fetchedResultsController2 fetchedObjects] count]; 
    } 

    return 0; 
} 

Xây dựng các tế bào:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    ... // table cell dequeue or creation, boilerplate stuff 

    // customize the cell 
    if (indexPath.section == 0) { 
     // get the managed object from fetchedResultsController1 
     // customize the cell based on the data 
    } else if (indexPath.section == 1) { 
     // get the managed object from fetchedResultsController2 
     // customize the cell based on the data 
    } 

    return cell; 
} 
+0

Cảm ơn cho câu trả lời chi tiết. Phần đó có vẻ khá đơn giản, tuy nhiên có 2 phương pháp khác mà tôi không chắc chắn về (những gì họ làm và nếu họ cần bất kỳ thay đổi nào): http://pastebin.ca/1805761 – indragie

+0

Nó phụ thuộc vào những gì ứng dụng nào; thật khó cho tôi để trả lời mà không biết nhiều hơn về ứng dụng, thiết kế, v.v. Tuy nhiên, bạn có thể có một sự lựa chọn an toàn trong việc có những phương thức gửi bảng xem một thông điệp reloadData. – Giao

+0

Được quản lý để làm việc này với một chút tinkering :-) Cảm ơn – indragie

3

Mở rộng giải pháp Giao với hai NSFetchedResultsControllers - chúng ta phải nhớ NSFetchedResultsController chúng tôi không biết về hai phần của chúng ta và các NSIndexPathes được trả về sẽ luôn là phần đầu tiên.

Vì vậy, khi chúng ta đang nhận được một đối tượng trong cấu hình di động:

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; 
    if (!cell) { 
     [tableView registerNib:[UINib nibWithNibName:@"cell" bundle:nil] forCellReuseIdentifier:@"cell"]; 
     cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; 
    } 
    [self configureCell:cell atIndexPath:indexPath]; 
    return cell; 
} 

-(void)configureCell:(UITableViewCell*)cell atIndexPath:(NSIndexPath *)indexPath { 
    if (indexPath.section == 0) { 
     NSManagedObject *object = [self.fetchedResults1 objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]]; 
     //use object to configure cell 
    } else { 
     NSManagedObject *object = [self.fetchedResults2 objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]]; 
     //use object to configure cell 
    } 
} 

Cập nhật các tế bào trong khi NSFetchedResultsController nhận thấy một số thay đổi:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { 
    NSIndexPath *customIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:(controller == self.fetchedResultsController1)?0:1]; 
    NSIndexPath *customNewIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row inSection:(controller == self.fetchedResultsController2)?0:1]; 
    switch(type) { 
     case NSFetchedResultsChangeInsert: 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:customNewIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
     case NSFetchedResultsChangeDelete: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:customIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
     case NSFetchedResultsChangeUpdate: 
      [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath]; 
      break; 
     case NSFetchedResultsChangeMove: 
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:customIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:customNewIndexPath] withRowAnimation:UITableViewRowAnimationFade]; 
      break; 
    } 
} 
+0

Câu trả lời hay nhưng sau khi khởi chạy lại ứng dụng 'performFetch' phải được gọi nếu không bối cảnh mất ManagedObjects được tìm nạp. Bất kỳ giúp đỡ? – Goppinath

1

Nhiều lấy bộ điều khiển (và có thể nhiều đơn vị) là cách tiếp cận sai . Giải pháp đúng là sử dụng thông số sectionNameKeyPath cho số NSFetchedResultController để nhóm các kết quả thành nhiều phần. Nếu bạn nghĩ về các thực thể của bạn khác nhau có lẽ chúng thực sự là cùng một thực thể và thay vào đó bạn có thể sử dụng một itemType thuộc tính mà sau đó bạn có thể phân đoạn (và bạn cũng phải sắp xếp nó). Ví dụ. nói rằng tôi đã có các thực thể Hops và Grains sau đó tôi có thể thay đổi những thành phần thành phần và có một thành phần int_16 propertyType mà sau đó tôi có một enum trong mã để lưu trữ các giá trị hopType = 0, grainType = 1. Sau khi tất cả các thành phần chỉ là một tên và một trọng lượng, mà cả hai chia sẻ.

Nếu các thực thể của bạn thực sự có một bộ thuộc tính riêng biệt, thì giải pháp chính xác là tạo đối tượng trừu tượng gốc có thuộc tính mà bạn có thể sử dụng cho mục, ví dụ: sortOrder, sectionID hoặc loại. Khi bạn tạo bộ điều khiển tìm nạp và tìm nạp thực thể trừu tượng cha, bạn thực sự nhận được kết quả chứa tất cả các thực thể con. Ví dụ: trong ứng dụng Ghi chú, họ có một thực thể trừu tượng NoteContainer có các thực thể con Tài khoản và Thư mục.Bằng cách này, họ có thể sử dụng bộ điều khiển tìm nạp đơn để hiển thị tài khoản trong ô đầu tiên trong phần, và sau đó có tất cả các thư mục trong các ô sau đây. Ví dụ. Tất cả các ghi chú iCloud (thực sự là tài khoản), sau đó Notes (là thư mục mặc định), tiếp theo là tất cả các thư mục tùy chỉnh, sau đó là thư mục thùng rác. Họ sử dụng một thuộc tính sortOrder và thư mục mặc định là 1, các thư mục tùy chỉnh là 2, và thùng rác là 3. Sau đó, bằng cách thêm vào như một bộ mô tả sắp xếp, chúng có thể hiển thị các ô theo thứ tự mà chúng muốn. Đó là một chút khác biệt so với yêu cầu của bạn bởi vì chúng có 2 thực thể được trộn vào các phần khác nhau, nhưng bạn vẫn có thể sử dụng nó chỉ với các thuộc tính sắp xếp khác nhau.

Các đạo đức của câu chuyện là không chống lại khuôn khổ, nắm lấy nó :-)

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