Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.6k views
in Technique[技术] by (71.8m points)

ios - Invalid update: invalid number of rows in section 0 terminating with uncaught exception of type NSException

I've read all of the related posts regarding this and am still having an error:

'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (5) must be equal to the number of rows contained in that section before the update (5), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

Here are the details:

i use code to open piano table when open cell it gives sub cells each row has different number of cells it was work well but i need to modify some thing that when i click on row it open then if i click on another row i need it to open the second and close the first opened row this is my code rootView.m

#pragma -mark TableViewDelegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 5;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    GCRetractableSectionController* sectionController = [self.retractableControllers objectAtIndex:section];
    //    NSLog(@"sectionController.numberOfRow %d",sectionController.numberOfRow );
    return sectionController.numberOfRow;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    GCRetractableSectionController* sectionController = [self.retractableControllers objectAtIndex:indexPath.section];
    return [sectionController cellForRow:indexPath.row];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"index path section %d indexrow %d",indexPath.section  ,indexPath.row);

    GCRetractableSectionController* sectionController = [self.retractableControllers objectAtIndex:indexPath.section];


  //  vc.open = !vc.open;


//    return [sectionController didSelectCellAtRow:indexPath.row];



    if (indexPath.row == 1) {
        [myCustomView setHidden:YES];
           NSLog(@"index path 11111 111111 1111111 indexrow %d",indexPath.row);



    }
    else if (indexPath.row == 2) {
    }

    return [sectionController didSelectCellAtRow:indexPath.row];




}

// GCRetractableSectionController.m

   #import "GCRetractableSectionController.h"
#import "RootViewController.h"

@interface GCRetractableSectionController ()

@property (nonatomic, assign) UIViewController *viewController;

- (void) setAccessoryViewOnCell:(UITableViewCell*) cell;

@end

@implementation GCRetractableSectionController

@synthesize useOnlyWhiteImages, titleTextColor, titleAlternativeTextColor;
@synthesize viewController;
@synthesize open, rowAnimation;
@synthesize backUp;
#pragma mark -
#pragma mark Initialisation

- (id) initWithViewController:(UIViewController*) givenViewController {
    if ((self = [super init])) {
        if (![givenViewController respondsToSelector:@selector(tableView)]) {
            //The view controller MUST have a tableView proprety
            [NSException raise:@"Wrong view controller" 
                        format:@"The passed view controller to GCRetractableSectionController must respond to the tableView proprety"];
        }
        self.viewController = givenViewController;
    //  self.open = NO;
        self.useOnlyWhiteImages = NO;
        self.rowAnimation = UITableViewRowAnimationTop;

    }
    return self;
}

#pragma mark -
#pragma mark Getters

- (UITableView*) tableView {
    return [self.viewController performSelector:@selector(tableView)];
}

- (NSUInteger) numberOfRow {
    NSLog(@"the count %d",self.contentNumberOfRow);

    return (self.open) ? self.contentNumberOfRow + 1 : 1;
}

- (NSUInteger) contentNumberOfRow {
    return 0;
}

- (NSString*) title {
    return NSLocalizedString(@"No title",);
}

- (NSString*) titleContentForRow:(NSUInteger) row {
    return NSLocalizedString(@"No title",);
}

#pragma mark -
#pragma mark Cells

- (UITableViewCell *) cellForRow:(NSUInteger)row {
    UITableViewCell* cell = nil;

    if (row == 0) cell = [self titleCell];
    else cell = [self contentCellForRow:row - 1];

    return cell;
}

- (UITableViewCell *) titleCell {
    NSString* titleCellIdentifier = [NSStringFromClass([self class]) stringByAppendingString:@"title"];

    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:titleCellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:titleCellIdentifier];
    }

    cell.textLabel.text = self.title;
    if (self.contentNumberOfRow != 0) {
        cell.detailTextLabel.text = [NSString stringWithFormat:NSLocalizedString(@"%i items",), self.contentNumberOfRow];
        cell.selectionStyle = UITableViewCellSelectionStyleBlue;
        [self setAccessoryViewOnCell:cell];
    }
    else {
        cell.detailTextLabel.text = NSLocalizedString(@"No item",);
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        cell.accessoryView = nil;
        cell.textLabel.textColor = [UIColor blackColor];
    }

    return cell;
}

- (UITableViewCell *) contentCellForRow:(NSUInteger)row {
    NSString* contentCellIdentifier = [NSStringFromClass([self class]) stringByAppendingString:@"content"];

    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:contentCellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:contentCellIdentifier] ;
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }

    cell.textLabel.text = [self titleContentForRow:row];

    return cell;
}

- (void) setAccessoryViewOnCell:(UITableViewCell*) cell {
    NSString* path = nil;
    if (self.open) {
        path = @"UpAccessory";
        if (self.titleAlternativeTextColor == nil) cell.textLabel.textColor =  [UIColor colorWithRed:0.191 green:0.264 blue:0.446 alpha:1.000];
        else cell.textLabel.textColor = self.titleAlternativeTextColor;
    }   
    else {
        path = @"DownAccessory";
        cell.textLabel.textColor = (self.titleTextColor == nil ? [UIColor blackColor] : self.titleTextColor);
    }

    UIImage* accessoryImage = [UIImage imageNamed:path];
    UIImage* whiteAccessoryImage = [UIImage imageNamed:[[path stringByDeletingPathExtension] stringByAppendingString:@"White"]];

    UIImageView* imageView;
    if (cell.accessoryView != nil) {
        imageView = (UIImageView*) cell.accessoryView;
        imageView.image = (self.useOnlyWhiteImages ? whiteAccessoryImage : accessoryImage);
        imageView.highlightedImage = whiteAccessoryImage;
    }
    else {
        imageView = [[UIImageView alloc] initWithImage:(self.useOnlyWhiteImages ? whiteAccessoryImage : accessoryImage)];
        imageView.highlightedImage = whiteAccessoryImage;
        cell.accessoryView = imageView;
    }
}

#pragma mark -
#pragma mark Select Cell

- (void) didSelectCellAtRow:(NSUInteger)row {
    if (row == 0) {
           [self didSelectTitleCell];
    }
    else [self didSelectContentCellAtRow:row - 1];
}

- (void) didSelectTitleCell {


    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    NSData *myDecodedObject  = [userDefaults objectForKey:@"tableViewDataPrevious"];
    NSMutableArray *decodedArray =[NSKeyedUnarchiver unarchiveObjectWithData: myDecodedObject];
    NSLog(@"the back Up Count %d",[decodedArray count]);
    if ([decodedArray count]!=0){

        NSLog(@"Back Up Array ");
        NSLog(@"am here herer hererer hererer %@ " , decodedArray);



        // it quit here
       [self.tableView deleteRowsAtIndexPaths:decodedArray withRowAnimation:self.rowAnimation];
        //


        [self.tableView reloadData];

        [self.tableView endUpdates];

//        NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
//        [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
        NSLog(@"am here herer hererer hererer");

    }

    NSLog(@"didSelectedTitleCell");
    self.open = !self.open;
    NSLog(@"1");
    if (self.contentNumberOfRow != 0) [self setAccessoryViewOnCell:[self.tableView cellForRowAtIndexPath:[self.tableView indexPathForSelectedRow]]];

    NSIndexPath* indexPath = [self.tableView indexPathForSelectedRow];

    NSUInteger section = indexPath.section;
    NSUInteger contentCount = self.contentNumberOfRow;

    [self.tableView beginUpdates];

    NSMutableArray* rowToInsert = [[NSMutableArray alloc] init];
    for (NSUInteger i = 1; i < contentCount + 1; i++) {
        NSIndexPath* indexPathToInsert = [NSIndexPath indexPathForRow:i inSection:section];
        [rowToInsert addObject:indexPathToInsert];
    }

    if (self.open) {


        NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
         NSData *myDecodedObject  = [userDefaults objectForKey:@"tableViewDataPrevious"];
        NSMutableArray *decodedArray =[NSKeyedUnarchiver unarchiveObjectWithData: myDecodedObject];

        NSLog(@"the back Up Count %d",[decodedArray count]);

        if ([decodedArray count]!=0){

            NSLog(@"Back Up Array ");
         [self.tableView deleteRowsAtIndexPaths:decodedArray withRowAnimation:self.rowAnimation];


             //[self.tableView endUpdates];

            NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
            [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];


        }
             [self.tableView insertRowsAtIndexPaths:rowToInsert withRowAnimation:self.rowAnimation];

        [self.tableView endUpdates];



         backUp = [[NSMutableArray alloc]init];
        [backUp addObjectsFromArray:rowToInsert];
         NSLog(@"the back Up Count %@", backUp );
        NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:backUp];

        [userDefaults setObject:myEncodedObject forKey:@"tableViewDataPrevious"];
        ;
        [userDefaults synchronize];




    }
    else {
         [self.tableView deleteRowsAtIndexPaths:rowToInsert withRowAnimation:self.rowAnimation];
        [self.tableView endUpdates];
}


    [self.tableView endUpdates];

    if (self.open) [self.tableView scrollToNearestSelectedRowAtScrollPosition:UITableViewScrollPositionTop animated:YES];
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (void) didSelectContentCellAtRow:(NSUInteger)row {

}

@end

and the output is

2014-10-09 13:10:13.747 Brnlysta2[10199:90b] the back Up Count (
        "<NSIndexPath: 0x8e8fb80> {length = 2, path = 0 - 1}",
        "<NSIndexPath: 0x8e87900> {length = 2, path = 0 - 2}",
        "<NSIndexPath: 0x8e871c0> {length = 2, path = 0 - 3}",
        "<NSIndexPath: 0x8e908e0> {length = 2, path = 0 - 4}"
    )
    2014-10-09 13:10:14.717 Brnlysta2[10199:90b] index path section 1 indexrow 0
    2014-10-09 13:10:14.718 Brnlysta2[10199:90b] the back Up Count 4
    2014-10-09 13:10:14.718 Brnlysta2[10199:90b] Back Up Array 
    2014-10-09 13:10:14.719 Brnlysta2[10199:90b] am here herer hererer hererer (
        "<NSIndexPath: 0x8b3bb60> {length = 2, path = 0 - 1}",
        "<NSIndexPath: 0x8b8e5c0> {length = 2, path = 0 - 2}",
        "<NSIndexPath: 0x8b75f60> {length = 2, path = 0 - 3}",
        "<NSIndexPath: 0x8b7b960> {length = 2, path = 0 - 4}"
    ) 
    2014-10-09 13:10:14.719 Brnlysta2[10199:90b] *** Assertion failure in -[UITableView _endCellAnimationsW

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

When you do something which edits/updates UITableView, it check some dataSource methods if data integrity is still exists or not. You have a problem with that. On your numberOfSectionsInTableView or tableView: numberOfRowsInSection: method, there is a miscalculation. Before calling deleteRowsAtIndexPaths, so also need to update the necessary properties which are used to calculate the section/row counts.

By the way, there is no meaning using reloadData after deleteRowsAtIndexPaths. It might interfere with your deletion animation.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...