Adding new row in TableView using insertRowsAtIndexPaths

Discussion in 'iPhone/iPad Programming' started by StasKalishenko, Dec 24, 2008.

  1. macrumors newbie

    Joined:
    Dec 4, 2008
    #1
    Hi, guys. I try to add new row dunamically using insertRowsAtIndexPaths. But I get a small bug: the next group of TableView left trail of caption. My major functions and 2 screenshots (before editing and after):

    Code:
    - (void)setEditing:(BOOL)editing animated:(BOOL)animated {
        //[super setEditing:editing animated:animated];
        //[self.navigationItem setHidesBackButton:editing animated:animated];
        //[tableView reloadData];
    	
    	[super setEditing:editing animated:animated];
        [self.navigationItem setHidesBackButton:editing animated:animated];
    	
    	// Calculate the index paths for all of the placeholder rows based on the number of items in each section.
    	NSArray *indexPaths = [NSArray arrayWithObjects: 
    						   [NSIndexPath indexPathForRow:0 inSection:1],
    						   nil];
        [tableView beginUpdates];
        [tableView setEditing:editing animated:YES];
        if (editing) {
            // Show the placeholder rows
            [tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];
        } else {
            // Hide the placeholder rows.
            [tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationTop];
        }
        [tableView endUpdates];
    	//[tableView reloadData];
    }
    
    // Update the data model according to edit actions delete or insert.
    - (void)tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle 
    forRowAtIndexPath:(NSIndexPath *)indexPath {
        if (editingStyle == UITableViewCellEditingStyleDelete) {
            /*NSDictionary *section = [data objectAtIndex:indexPath.section];
            if (section) {
                NSMutableArray *content = [section valueForKey:@"content"];
                if (content && indexPath.row < [content count]) {
                    [content removeObjectAtIndex:indexPath.row];
                }
            }*/
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        } else if (editingStyle == UITableViewCellEditingStyleInsert) {
    		//EditingViewController *controller = [MasterViewController editingViewController];
    		EditingViewController *controller = self.editingViewController;
    		controller.editedObject = client;
    		switch (indexPath.section) {
    			case 0: {
    				controller.textValue = @"";
    				controller.editedFieldKey = @"Name";
    				controller.dateEditing = NO;
    			} break;
    			case 1: {
    				controller.textValue = @"";
    				controller.editedFieldKey = @"Communication";
    				controller.dateEditing = NO;
    			} break;
    			case 2: {
    				controller.textValue = @"";
    				controller.editedFieldKey = @"Adress";
    				controller.dateEditing = NO;
    			} break;
    			case 3: {
    				controller.textValue = @"";
    				controller.editedFieldKey = @"Comments";
    				controller.dateEditing = NO;
    			} break;
    		}
    		self.selectedIndexPath = indexPath;
    		[self.navigationController pushViewController:controller animated:YES];
    		[controller release];
        }
    }
    
    #pragma mark -
    #pragma mark <UITableViewDelegate, UITableViewDataSource> Methods
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tv {
        // 4 sections, one for each property
        return 4;
    }
    
    - (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section {
        // Only one row for each section
    	NSInteger count = 1;
        // If we're in editing mode, we add a placeholder row for creating new items.
    	if ((section == 1) && (self.editing)) count++;
    	return count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    	DetailCell *cell = (DetailCell *)[tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];
        if (cell == nil) {
            cell = [[[DetailCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"MyIdentifier"] autorelease];
            cell.hidesAccessoryWhenEditing = NO;
        }
    	NSString *sectionName;
    	switch (indexPath.section) {
            case 0: sectionName = @"Name"; break;
            case 1: sectionName = @"Communication"; break;
            case 2: sectionName = @"Address"; break;
    		case 3: sectionName = @"Comments"; break;	
        }
    	if ((indexPath.section == 1) && (indexPath.row > 0)) {
    		cell.prompt.text = [NSString stringWithFormat:@"Add new %@", sectionName];
    		cell.promptMode = YES;
    	} else {
    		switch (indexPath.section) {
    			case 0: self.title = cell.name.text = client.name;
    				cell.promptMode = NO;
    				break;
    			case 1: cell.name.text = client.communication;
    				cell.promptMode = NO;
    				break;
    			case 2: cell.name.text = client.address;
    				cell.promptMode = NO;
    				break;
    			case 3: cell.name.text = client.comments; 
    				cell.promptMode = NO;
    				break;
    		}
    	}
        return cell;
    }
    
    - (NSString *)tableView:(UITableView *)tv titleForHeaderInSection:(NSInteger)section {
        // Return the displayed title for the specified section.
    	switch (section) {
            case 0: return @"Name";
            case 1: return @"Communication";
            case 2: return @"Address";
    		case 3: return @"Comments";	
        }
        return @"";
    }
    
    // Called after selection. In editing mode, this will navigate to a new view controller.
    - (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    	if (self.editing) {
            // Don't maintain the selection. We will navigate to a new view so there's no reason to keep the selection here.
            [tableView deselectRowAtIndexPath:indexPath animated:NO];
            // Go to edit view
            //NSDictionary *section = [data objectAtIndex:indexPath.section];
            BOOL section = TRUE;
    		if (section) {
    			//EditingViewController *controller = [MasterViewController editingViewController];
    			EditingViewController *controller = self.editingViewController;
    			controller.editedObject = client;
    			switch (indexPath.section) {
    				case 0: {
    					controller.textValue = client.name;
    					controller.editedFieldKey = @"Name";
    					controller.dateEditing = NO;
    				} break;
    				case 1: {
    					controller.textValue = client.communication;
    					controller.editedFieldKey = @"Communication";
    					controller.dateEditing = NO;
    				} break;
    				case 2: {
    					controller.textValue = client.address;
    					controller.editedFieldKey = @"Adress";
    					controller.dateEditing = NO;
    				} break;
    				case 3: {
    					controller.textValue = client.comments;
    					controller.editedFieldKey = @"Comments";
    					controller.dateEditing = NO;
    				} break;
    			}
    			self.selectedIndexPath = indexPath;
    			[self.navigationController pushViewController:controller animated:YES];
    		}
    	} else {
            // This will give the user visual feedback that the cell was selected but fade out to indicate that no
            // action is taken.
            [tableView deselectRowAtIndexPath:indexPath animated:YES];
        }
    }
    
    - (UITableViewCellAccessoryType)tableView:(UITableView *)tv accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath {
        // Show the disclosure indicator if editing.
        return (self.editing) ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
    }
    
    // The editing style for a row is the kind of button displayed to the left of the cell when in editing mode.
    - (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
        // No editing style if not editing or the index path is nil.
        if (self.editing == NO || !indexPath) return UITableViewCellEditingStyleNone;
    	if (indexPath.row > 0) {
    		return UITableViewCellEditingStyleInsert;
    	} else {
    		return UITableViewCellEditingStyleDelete;
    	}
    	return UITableViewCellEditingStyleNone;
    }
     

    Attached Files:

  2. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #2
    Haven't had a chance to look at your problem but I just wanted to suggest enclosing your code in the code/code tags (see the # in the toolbar) to avoid the smilies.
     
  3. thread starter macrumors newbie

    Joined:
    Dec 4, 2008
    #3
    Thanks a lot.

    But, did anybody face with the same problem. Where can I "dig"?
     
  4. Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #4
    What do you mean by "left trail of caption"?
     
  5. macrumors newbie

    Joined:
    Aug 29, 2009
    #5
    A matter of timing for me

    OK I ran into this problem too and for me it came to a matter of timing.

    I had a function that was searching for bonjour machines and loading into section 1 of my tableView. Once they were all found, I was filling a local NSArray then calling [[self tableView] reloadSections:withRowAnimation where I shouldn't have been.

    To fix MY redraw problem (which looked exactly like yours), instead of filling my array, then calling reloadSections, I changed my thinking and inserted new rows at that point via the insertRowsAtIndexPaths:withRowAnimation

    Once I changed how the tableView was being manipulated, my other insert and deletion functions started working/drawing normally.

    Here is an example of my before and after:
    Before:
    Code:
    - (void) allServersFound {
    	// called when bonjourservices has listings of machines:
    	bonjourMachines = [bonjourService foundServers] // NSArray of server names;
    	[machineListings reloadSections:[[[NSIndexSet alloc] initWithIndex:1] autorelease] withRowAnimation:UITableViewRowAnimationNone];
    }
    
    After:
    Code:
    - (void) allServersFound {
    	// called when bonjourservices has listings of machines:
    	bonjourMachines = [bonjourService foundServers] // NSArray of server names;
    		
    	// insert them
    	NSArray *newData = [NSArray arrayWithObjects:[NSIndexPath indexPathForRow:([bonjourMachines count] - 1) inSection:1], nil];
    	[[self tableView] insertRowsAtIndexPaths:newData withRowAnimation:UITableViewRowAnimationNone];	
    }
    
    FYI Garbage collection not shown to keep code simple
     

Share This Page