iOS : Inserting multiple rows in UITableview with insertRowsAtIndexPaths iOS : Inserting multiple rows in UITableview with insertRowsAtIndexPaths objective-c objective-c

iOS : Inserting multiple rows in UITableview with insertRowsAtIndexPaths


The code is close, but the table view needs to be updated with index paths in exact correspondence with what's added to the datasource.

-(void)insertDownloadedActions:(NSMutableArray *)dataToAdd{    // don't need this    //__weak CurrentViewController *weakSelf = self;    int64_t delayInSeconds = 2.0;    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);    dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {        // build the index paths for insertion        // since you're adding to the end of datasource, the new rows will start at count        NSMutableArray *indexPaths = [NSMutableArray array];        NSInteger currentCount = self.datasource.count;        for (int i = 0; i < dataToAdd.count; i++) {            [indexPaths addObject:[NSIndexPath indexPathForRow:currentCount+i inSection:0]];        }        // do the insertion        [self.dataSource addObjects:dataToAdd];        // tell the table view to update (at all of the inserted index paths)        [self.tableView beginUpdates];        [self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];        [self.tableView endUpdates];    });}

You want a weakSelf to avoid cycle where the block owner retains the block and the block (by using the block owner "self") retains the owner. There's no need for the weakSelf pattern here since the view controller is not retaining a copy of the dispatched block.


In swift, to add multiple rows, We can do

let indexPaths = (0 ..< messageList.count).map { IndexPath(row: $0, section: 0) }self.chatTableView.beginUpdates()self.chatTableView.insertRows(at: indexPaths, with: .bottom)self.chatTableView.endUpdates()

Here I'm inserting to indexPath:0 as I want to append the list on scrolling up. (Reverse pagination)


The insertRowsAtIndexPaths:withRowAnimation: AND the changes to your data model both need to occur in-between beginUpdates and endUpates

I've created a simple example that should work on its own. I spent a week fiddling around trying to figure this out since I couldn't find any simple examples, so I hope this saves someone time and headache!

@interface MyTableViewController ()@property (nonatomic, strong) NSMutableArray *expandableArray;@property (nonatomic, strong) NSMutableArray *indexPaths;@property (nonatomic, strong) UITableView *myTableView;@end@implementation MyTableViewController- (void)viewDidLoad{    [self setupArray];}- (void)setupArray{    self.expandableArray = @[@"One", @"Two", @"Three", @"Four", @"Five"].mutableCopy;}- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{    return 1;}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    return self.expandableArray.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    //here you should create a cell that displays information from self.expandableArray, and return it}//call this method if your button/cell/whatever is tapped- (void)didTapTriggerToChangeTableView{    if (/*some condition occurs that makes you want to expand the tableView*/) {        [self expandArray]    }else if (/*some other condition occurs that makes you want to retract the tableView*/){        [self retractArray]    }}//this example adds 1 item- (void)expandArray{    //create an array of indexPaths    self.indexPaths = [[NSMutableArray alloc] init];    for (int i = theFirstIndexWhereYouWantToInsertYourAdditionalCells; i < theTotalNumberOfAdditionalCellsToInsert + theFirstIndexWhereYouWantToInsertYourAdditionalCells; i++) {        [self.indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];    }    //modify your array AND call insertRowsAtIndexPaths:withRowAnimation: INBETWEEN beginUpdates and endUpdates    [self.myTableView beginUpdates];    //HERE IS WHERE YOU NEED TO ALTER self.expandableArray to have the additional/new data values, eg:    [self.expandableArray addObject:@"Six"];    [self.myTableView insertRowsAtIndexPaths:self.indexPaths withRowAnimation:(UITableViewRowAnimationFade)];  //or a rowAnimation of your choice    [self.myTableView endUpdates];}//this example removes all but the first 3 items- (void)retractArray{    NSRange range;    range.location = 3;    range.length = self.expandableArray.count - 3;    //modify your array AND call insertRowsAtIndexPaths:withRowAnimation: INBETWEEN beginUpdates and endUpdates    [self.myTableView beginUpdates];    [self.expandableArray removeObjectsInRange:range];    [self.myTableView deleteRowsAtIndexPaths:self.indexPaths withRowAnimation:UITableViewRowAnimationFade];  //or a rowAnimation of your choice    [self.myTableView endUpdates];}@end

Free code, don't knock it.