开发者

Multiple NsfetchedResultsController on a UItableView

开发者 https://www.devze.com 2023-01-14 22:34 出处:网络
I\'m having difficulty implementing 2 nsfetchedresultsController in a tableView. I wanted a fetchedresultsController in each section of the table (2 sections), something like this:

I'm having difficulty implementing 2 nsfetchedresultsController in a tableView. I wanted a fetchedresultsController in each section of the table (2 sections), something like this:

Wishlist

  • product
  • product2

Bought

  • product3

I know that for this example i wouldn't need 2 nsfetchedResultsController but i will need this later..

when i remove a product from one nsfetchedResultsController it passes to the other and i get this error:

Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (0) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted). with userInfo (null)"

I thinks this happens because when the first fetchedRController detects a change it updates the tableView before the second one is called is that right ? should i use NSMutableArrays and update the tableView manually?

The code:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
NSInteger numberOfRows = 0;

switch (section)
{
    case WISHLIST_SECTION:

    {
        numberOfRows =[[fetchedResultsControllerwish fetchedObjects]count];


    };
         break;

    case PURCHASED_SECTION:
    {   
        numberOfRows =[[fetchedResultsControllerPurchased fetchedObjects]count];

    };
        break;


    default:
        break;
}
return numberOfRows;
}

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller is about to start sending change notifications, so prepare the table view for updates.
[self.tableView beginUpdates];
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
{

// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
[self.tableView endUpdates];
}

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

UITableView *tableViewT = self.tableView;

switch(type) {

    case NSFetchedResultsChangeInsert:
        [tableViewT insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                         withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeDelete:
        [tableViewT deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                         withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeUpdate:
        [self configureCell:(GiftEventTableViewCell *)[tableViewT cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
        break;

    case NSFetchedResultsChangeMove:
        [tableViewT deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                         withRowAnimation:UITableViewRowAnimationFade];
        [tableViewT insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                         withRowAnimation:UITableViewRowAnimationFade];
        break;
}
}

-(void)configureCell:(GiftEventTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {
    case WISHLIST_SECTION:
    {
        GiftEvent *giftEv=(GiftEvent *)[fetchedResultsControllerwish objectAtIndexPath:indexPath];
        cell.gift=giftEv;

    };
        break;
    case PURCHASED_SECTION:
    {
        GiftEvent *giftEv=(GiftEvent *)[fetchedResultsControllerPurchased objectAtIndexPath:indexPath];

        //if i don't use indexpath.row in the second section i get an out of bounds error
        //GiftEvent *giftEv=(GiftEvent *)[[fetchedResultsControllerPurchased fetchedObjects]objectAtIndex: indexPath.row];
        cell.gift=giftEv;

    };
        break;




    default:
        break;
}

}

// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) 
{
    switch (indexPath.section) {
        case WISHLIST_SECTION:
        {
            // Delete the managed object for the given index path

            [self.managedObjectContext deleteObject:[fetchedResultsControllerwish objectAtIndexPath:indexPath]];

            // Save the context.
            NSError *error;
            if (![self.managedObjectContext save:&error]) {
                /*
                 Replace this implementation with code to handle the error appropriately.

                 abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
                 */
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
            [self.tableView reloadData];

             };
            break;
        case PURCHASED_SECTION:
        {
            // Delete the managed object for the given index path

            [self.managedObjectContext deleteObject:[fetchedResultsControllerPurchased objectAtIndexPath:indexPath]];

            // Save the context.
            NSError *error;
            if (![self.managedObjectContext save:&error]) {
                /*
                 Replace this implementation with code to handle the error appropriately.

                 abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to q开发者_C百科uit the application by pressing the Home button.
                 */
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }

        };
            break;

        default:
            break;
    }
}   
}


Check out this other question on Stack Overflow:


Core Data: UITableView with multiple NSFetchedResultControllers

Core Data: UITableView with multiple NSFetchedResultControllers


Using multiple is the wrong approach. The correct solution is to use the sectionNameKeyPath param to the NSFetchedResultController to group the results into multiple sections, in your case it would be a purchased boolean property on the product. And you should also make this the first sort descriptor in ascending order since you want un-purchased above purchased. Use the header title table delegate method to return the strings "Wishlist" and "Purchased" for each section index.

If you think you might have a 3rd list in the future, then you would better using a numeric status property, and in code an enum for each of the states (or lists) the product can be in. That's usually how this is done rather than sorting on a bool.


I just created a pod to solve this. https://github.com/imton/GMCoreDataMultipleSectionsTableVC

You can check it out and tell me what you think, feedback welcome!

G


Sorry guys, it was a noob error. The error was happening because the indexPath.section returned the section in the tableView but I had no sections in the fetchedResultsController (always index 0).

EDIT: actually there is one..

NSIndexPath *indexPathTemp = [NSIndexPath indexPathForRow:indexPath.row inSection:0];

Not sure if it's the best way but solved the problem.

0

精彩评论

暂无评论...
验证码 换一张
取 消