I am trying to insert row in the section. cell is a custom cell having textfield.
Below is the code snippet,
-(NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
NSLog(#"row in section::%i %i", section, sectionRows);
if(section == 0)
return 1;
else if(section == 1)
return 1;
else
return sectionRows;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"cell rows in section%i %i", indexPath.section, [tableView numberOfRowsInSection:indexPath.section]);
static NSString *MyIdentifier = #"MyIdentifier";
MyIdentifier = #"TableView";
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 31)];
[backgroundView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"bg_accordian.png"]]];
CustomMyMedCellView *customCell;
UIView *viewToHide;
if(indexPath.section == 0)
{
customCell = (CustomMyMedCellView *)[tableView dequeueReusableCellWithIdentifier: MyIdentifier];
if (customCell == nil)
{
NSLog(#"in Section 1::::::");
[[NSBundle mainBundle] loadNibNamed:#"CustomMyMedCellView" owner:self options:nil];
customCell = customMyMedCellView;
[customCell setTextFieldValue:#"Teva Generic Med" editable:NO];
viewToHide= (UIView *)[customCell.contentView viewWithTag:4];
viewToHide.hidden = YES;
}
}else if(indexPath.section == 1)
{
customCell = (CustomMyMedCellView *)[tableView dequeueReusableCellWithIdentifier: MyIdentifier];
if(indexPath.row == 0)
{
if (customCell == nil)
{
[[NSBundle mainBundle] loadNibNamed:#"CustomMyMedCellView" owner:self options:nil];
customCell = customMyMedCellView;
CGRect frame = customCell.textField.frame;
frame.origin.x = 30.0;
customCell.textField.frame = frame;
[customCell setTextFieldValue:#"Accutane Capsules" editable:NO];
viewToHide = (UIView *)[customCell.contentView viewWithTag:2];
viewToHide.hidden = YES;
}
}
}else
{
customCell = (CustomMyMedCellView *)[tableView dequeueReusableCellWithIdentifier: MyIdentifier];
NSLog(#"in Section 3%#", customCell);
if (customCell == nil)
{
NSLog(#"in Section 3 if");
[[NSBundle mainBundle] loadNibNamed:#"CustomMyMedCellView" owner:self options:nil];
customCell = customMyMedCellView;
customMyMedCellView.textField.delegate = self;
CGRect frame = customCell.textField.frame;
frame.origin.x = 30.0;
customCell.textField.frame = frame;
[customCell setTextFieldValue:#"" editable:YES];
viewToHide = (UIView *)[customCell.contentView viewWithTag:2];
viewToHide.hidden = YES;
viewToHide = (UIView *)[customCell.contentView viewWithTag:4];
viewToHide.hidden = YES;
viewToHide = (UIView *)[customCell.contentView viewWithTag:5];
viewToHide.hidden = YES;
viewToHide = (UIView *)[customCell.contentView viewWithTag:6];
viewToHide.hidden = YES;
customCell.tag = indexPath.row;
[self.myMedsTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:(sectionRows-1) inSection:2] atScrollPosition:UITableViewScrollPositionBottom animated:NO];
}
}
if(!self.isEditClicked)
{
viewToHide = (UIView *)[customCell.contentView viewWithTag:1];
viewToHide.hidden = YES;
}else{
viewToHide = (UIView *)[customCell.contentView viewWithTag:1];
viewToHide.hidden = NO;
}
customCell.backgroundView = backgroundView;
return customCell;
}
on clicking button i want to add row to section 2, for that below is the code i have added,
- (void)addButtonClick:(id)sender {
UIButton *clickedButton = (UIButton *) sender;
if(clickedButton.tag == 2)
{
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
NSInteger rowsInSection = [self.myMedsTableView numberOfRowsInSection:2];
if(rowsInSection>0){
NSLog(#"%#", [[self.myMedsTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:rowsInSection-1 inSection:2]] viewWithTag:rowsInSection-1 ]);
CustomMyMedCellView *uiView = (CustomMyMedCellView *)[[self.myMedsTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:rowsInSection-1 inSection:2]] viewWithTag:rowsInSection-1 ];
// NSLog(#"%#", uiView.subviews);
// UITextField *textField = (UITextField *)[uiView viewWithTag:3];
if([uiView.textField .text length] > 0)
{
sectionRows+=1;
}
}else{
sectionRows=1;
}
NSLog(#"Sectipn rows::::%i", sectionRows);
for (NSInteger i = 0; i < sectionRows; i++) {
NSLog(#"Sectipn rows:::: inside for");
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:2]];
}
NSLog(#"%i",[indexPathsToInsert count]);
[self.myMedsTableView beginUpdates];
[self.myMedsTableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationBottom];
[self.myMedsTableView endUpdates];
//[self.myMedsTableView reloadData];
}else{
Search *tableViewController = [[Search alloc] initWithNibName:#"Search" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:tableViewController animated:YES];
}
But i am getting below error,
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 2. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (2 inserted, 0 deleted).'
Please help me i am new to the iphone.
Thanks in Advance
This error occurs because there is inconsistency between the cells that are given through "cellForRowAtIndexPath" and the index paths you are trying to update. When updating your table with new cells, make sure that your "cellForRowAtIndexPath" can create a cell for these indexes and also make sure that the numberOfRowsInSection is also consistent with this information.
Related
Please take a look at the image.
I have a UITableView with custom cells and 2 sections. Once the UITableView populates enough cells that they all can't be shown on the screen, the last cell in the last section appears at the very top of the screen. The cell shouldn't even be visible in the UITableView since it's the last cell, and it is appearing completely outside the UITableView, at the top of the screen. I'm at a loss for even knowing where to begin to look in my code for this issue. I've only created a couple of UITableViews so I'm definitely not an expert on all the potential causes for this bug. The Table is set up through IB and the initialization code is in viewWillAppear, although there isn't much set up code. I am currently reading up on UITableView's scrollView, along with contentInset to see if there might be an explanation for this behavior. Has anyone encountered such a bug? I feel like it's unique enough that it may not be necessary to comb through all my code to determine. Regardless, I will post the relevant code below. Thank you for your help!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *uniqueIdentifierForPlayerCell = #"customPlayerCell";
//Initialize PlayerTableViewCell and set it's properties
PlayerTableViewCell *playerCell = nil;
playerCell = (PlayerTableViewCell *)[tableView dequeueReusableCellWithIdentifier:uniqueIdentifierForPlayerCell];
if (playerCell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"PlayerTableViewCell" owner:nil options:nil];
for(id currentObject in topLevelObjects) {
if([currentObject isKindOfClass:[PlayerTableViewCell class]]) {
playerCell = (PlayerTableViewCell *)currentObject;
break;
}
}
}
playerCell.textLabel.opaque = NO;
playerCell.textLabel.textColor = self.textColor;
playerCell.textLabel.font = [UIFont systemFontOfSize:18.0];
playerCell.textLabel.backgroundColor = [UIColor clearColor];
playerCell.selectionStyle = UITableViewCellSelectionStyleNone;
playerCell.accessoryButton.hidden = YES;
playerCell.reorderButton.hidden = YES;
NSString *uniqueIdentifierForAlleyCell = #"customAlleyCell";
//Initialize AlleyTableViewcell and set it's properties
AlleyTableViewCell *alleyCell = nil;
alleyCell = (AlleyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:uniqueIdentifierForAlleyCell];
if (alleyCell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"AlleyTableViewCell" owner:nil options:nil];
for(id currentObject in topLevelObjects) {
if([currentObject isKindOfClass:[AlleyTableViewCell class]]) {
alleyCell = (AlleyTableViewCell *)currentObject;
break;
}
}
}
alleyCell.textLabel.opaque = NO;
alleyCell.textLabel.textColor = self.textColor;
alleyCell.textLabel.font = [UIFont systemFontOfSize:18.0];
alleyCell.textLabel.backgroundColor = [UIColor clearColor];
alleyCell.selectionStyle = UITableViewCellSelectionStyleNone;
alleyCell.accessoryButton.hidden = YES;
alleyCell.deleteButton.hidden = YES;
//Alternate background colors for each section where section 0 is Alley section and section 1 is Player section. Stores the RGB values of the specific background color to the specific cell for future use
if(indexPath.section == 0 && (indexPath.row %2 == 0)) {
alleyCell.contentView.backgroundColor = self.backgroundColor;
alleyCell.isRed = 95.0/255.0;
alleyCell.isGreen = 94.0/255.0;
alleyCell.isBlue = 94.0/255.0;
self.alleyField.backgroundColor = self.backgroundColor;
}
else if(indexPath.section == 0 && (indexPath.row %2 == 1)){
alleyCell.contentView.backgroundColor = self.alternateColor;
alleyCell.isRed = 92.0/255.0;
alleyCell.isGreen = 92.0/255.0;
alleyCell.isBlue = 92.0/255.0;
self.alleyField.backgroundColor = self.alternateColor;
}
else if(indexPath.section == 1 && (indexPath.row %2 == 0)) {
playerCell.contentView.backgroundColor = self.backgroundColor;
playerCell.isRed = 95.0/255.0;
playerCell.isGreen = 94.0/255.0;
playerCell.isBlue = 94.0/255.0;
self.playerField.backgroundColor = self.backgroundColor;
}
else if(indexPath.section == 1 && (indexPath.row %2 == 1)) {
playerCell.contentView.backgroundColor = self.alternateColor;
playerCell.isRed = 92.0/255.0;
playerCell.isGreen = 92.0/255.0;
playerCell.isBlue = 92.0/255.0;
self.playerField.backgroundColor = self.alternateColor;
}
//If Alley array is empty, add alley TextField and return cell
if(indexPath.section == 0) {
if([self.allAlleys count] == 0) {
[alleyCell addSubview:self.alleyField];
self.alleyField.text = nil;
return alleyCell;
}
//Else set the alley name to the nameLabel text and return cell
else {
if(indexPath.row < [self.allAlleys count]) {
alleyCell.textLabel.text = [self.allAlleys objectAtIndex:indexPath.row];
if([alleyCell.textLabel.text isEqualToString: self.selectedAlley]) {
alleyCell.accessoryButton.hidden = NO;
}
else {
alleyCell.accessoryButton.hidden = YES;
}
return alleyCell;
}
//Add alley TextField to the last cell of the UITableView and return cell
else {
[alleyCell addSubview:self.alleyField];
self.alleyField.text = nil;
return alleyCell;
}
}
}
//If Player array is empty, add Player TextField and return cell
else if(indexPath.section == 1) {
if([self.bowlrNames count] == 0) {
[playerCell addSubview:self.playerField];
self.playerField.text = nil;
return playerCell;
}
//Else set the Player name to the nameLabel text and return cell
else {
if(indexPath.row < [self.bowlrNames count]) {
playerCell.textLabel.text = [self.bowlrNames objectAtIndex:indexPath.row];
for(int i = 0; i < [self.selectedBowlrs count]; i++) {
if([playerCell.textLabel.text isEqualToString: [self.selectedBowlrs objectAtIndex:i]]) {
playerCell.accessoryButton.hidden = NO;
playerCell.reorderButton.hidden = NO;
}
}
return playerCell;
}
//Add Player textField to the last cell of the UITableView and return cell
else {
[playerCell addSubview:self.playerField];
self.playerField.text = nil;
return playerCell;
}
}
}
}
//Actions for selecting a row in the UITable
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//If it is in the Alley section
if(indexPath.section == 0) {
//If the selected cell is the same as the last selected cell
if(self.lastIndexPathForAlleyCells && indexPath.row == self.lastIndexPathForAlleyCells.row) {
[tableView beginUpdates];
self.lastIndexPathForAlleyCells = nil;
AlleyTableViewCell *previousCell = (AlleyTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
//[tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:YES];
previousCell.selected = NO;
self.selectedAlley = nil;
previousCell.accessoryButton.hidden = YES;
[tableView endUpdates];
return;
}
//Else the selected cell is not the last selected cell
AlleyTableViewCell *previousCell = (AlleyTableViewCell *)[tableView cellForRowAtIndexPath:self.lastIndexPathForAlleyCells];
previousCell.selected = NO;
previousCell.accessoryButton.hidden = YES;
AlleyTableViewCell *cell = (AlleyTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
cell.selected = YES;
cell.accessoryButton.hidden = NO;
self.selectedAlley = cell.textLabel.text;
self.lastIndexPathForAlleyCells = indexPath;
[self.tableView reloadData];
}
else if(indexPath.section == 1) {
PlayerTableViewCell *cell = (PlayerTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
//If player is not already selected
if([self playerIsSelected:cell.textLabel.text] == NO) {
//Set selected to YES and reveal buttons
cell.selected = YES;
cell.accessoryButton.hidden = NO;
cell.reorderButton.hidden = NO;
//If 8 Players are currently selected, UIAlertView informs user they have reached the limit
if([self.selectedBowlrs count] == 8) {
NSString *message = #"You can only select up to 8 players";
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Max Players Selected" message:message delegate:self cancelButtonTitle:[self okButtonTitle] otherButtonTitles:nil, nil];
alertView.tag = TAG_FULLGAME;
[alertView show];
}
else {
//Insert name into selectedBowlrs array
[self.selectedBowlrs insertObject:cell.textLabel.text atIndex:0];
//Reorder bowlrNames array
NSString *bowlrName = [self.bowlrNames objectAtIndex:indexPath.row];
[self.bowlrNames removeObjectAtIndex:indexPath.row];
[self.bowlrNames insertObject:bowlrName atIndex:0];
//Move selected row to top of section
[self moveIndexPathToTop:indexPath];
}
}
//Else the player is already selected
else {
//Set selected to NO and hide buttons
cell.selected = NO;
cell.accessoryButton.hidden = YES;
cell.reorderButton.hidden = YES;
[self.selectedBowlrs removeObject:cell.textLabel.text];
[self.bowlrNames removeObject:cell.textLabel.text];
[self.bowlrNames insertObject:cell.textLabel.text atIndex:[self.selectedBowlrs count]];
[self moveIndexPathToMiddle:indexPath];
for(int i = 0; i < [self.selectedBowlrs count]; i++) {
NSLog(#"%#", [self.selectedBowlrs objectAtIndex:i]);
}
}
}
[self performSelector:#selector(reloadData) withObject:nil afterDelay:.25];
}
//Returns the number of rows for each section
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch (section) {
//For Alley section
case 0:
//If the array is empty, return 1 row for the Alley Textfield
if([self.allAlleys count] == 0)
return 1;
//Else return the number of elements in the array + 1 for the Alley Textfield
else
return [self.allAlleys count] + 1;
break;
//For Player section
case 1:{
//If the array is empty, return 1 row for the Player Textfield
if([self.bowlrNames count] == 0)
return 1;
//Else return the number of elements in the array + 1 for the Player Textfield
else
return [self.bowlrNames count] + 1;
break;
}
default:
break;
}
return 0;
}
//Set up appearance for section headers
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.tableView.bounds.size.width, 25.0)];
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
CGFloat isRed = 84.0/255.0;
CGFloat isGreen = 84.0/255.0;
CGFloat isBlue = 84.0/255.0;
self.headerColor = [[UIColor alloc]initWithRed:isRed green:isGreen blue:isBlue alpha:0.5];
headerLabel.backgroundColor = self.headerColor;
headerLabel.opaque = NO;
headerLabel.textColor = self.textColor;
headerLabel.highlightedTextColor = [UIColor whiteColor];
headerLabel.font = [UIFont systemFontOfSize:18.0];
headerLabel.frame = CGRectMake(0.0, 0.0, self.tableView.bounds.size.width, 25.0);
if (section == 0) {
[headerView setBackgroundColor:self.backgroundColor];
headerLabel.text = #"Alley";
[headerView addSubview:headerLabel];
}
else {
[headerView setBackgroundColor:self.backgroundColor];
headerLabel.text = #"Bowlr";
[headerView addSubview:headerLabel];
}
return headerView;
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
//Used to delete row of UITable
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
self.indexPathForEditing = indexPath;
if(editingStyle == UITableViewCellEditingStyleDelete) {
//For Alley section
if(indexPath.section == 0) {
//Set up UIAlertView
NSString *message = #"Are you sure?";
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Delete Alley?" message:message delegate:self cancelButtonTitle:[self cancelButtonTitle] otherButtonTitles:[self deleteButtonTitle], nil];
alertView.tag = TAG_Alley;
[alertView show];
}
//For Player section
else if(indexPath.section == 1) {
//Set up UIAlertView
NSString *message = #"All information for this Bowlr will be deleted";
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Delete Bowlr?" message:message delegate:self cancelButtonTitle:[self cancelButtonTitle] otherButtonTitles:[self deleteButtonTitle], nil];
alertView.tag = TAG_Player;
[alertView show];
}
}
[self performSelector:#selector(reloadData) withObject:nil afterDelay:.25];
}
Okay, I think there's two basic things you need to remember here.
(1) You must never add something to the cell as a subview. Add it only to the cell's contentView. This code is wrong: [alleyCell addSubview:self.alleyField];
(2) These cells are being reused. You may have 100 rows but only 10 cells, being constantly reused as the user scrolls. Therefore you must completely set up every cell from an empty state, and if it isn't in the empty state to start with, you need to get it into the empty state. If you add a textfield to a cell in one pass thru cellForRowAtIndexPath, you must remember to remove the textfield in every other pass thru cellForRowAtIndexPath, or the textfield can show up in other rows because another row might reuse that same cell.
(See also the discussion towards the end of this section of my book: http://www.apeth.com/iOSBook/ch21.html#_the_three_big_questions It discusses a simple consequence of forgetting that the cells are reused.)
Also, I need hardly add that frame matters. You are adding a subview, but I have no idea what its frame is. With the right (meaning wrong) frame value, that subview could appear outside the cell. Also, are you using cells of different heights? If so, remember that because the cell is being reused, its height can change. Thus, autoresizing behavior can cause the frame to change.
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
// NSLog(#"msgcnt123 %#\n",[messageCount objectAtIndex:indexPath.row]);
NSArray *seperateArray = [[clist objectForKey:[[clist allKeys]objectAtIndex:indexPath.row]]componentsSeparatedByString:#"#"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// NSLog(#"key %#\n",[[clist allKeys]objectAtIndex:indexPath.row]);
cell.textLabel.text = [seperateArray objectAtIndex:0];
// cell.textLabel.text = [contactlist objectAtIndex:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// NSLog(#"sep %#\n",seperateArray);
if (![[seperateArray objectAtIndex:1] isEqualToString:#"0"]) {
NSLog(#"msgCount %#\n",[seperateArray objectAtIndex:1]);
lblCnt = [[UILabel alloc]initWithFrame:CGRectMake(260, 13, 20, 20)];
lblCnt.backgroundColor = [UIColor lightGrayColor];
lblCnt.textColor = [UIColor blackColor];
lblCnt.text = [seperateArray objectAtIndex:1];
lblCnt.textAlignment = UITextAlignmentCenter;
lblCnt.layer.masksToBounds = YES;
lblCnt.layer.cornerRadius = 2.0f;
[cell.contentView addSubview:lblCnt];
lblCnt.tag = 1000;
}
else
{
/*NSLog(#"msgCount1 %#\n",[seperateArray objectAtIndex:1]);
[lblCnt removeFromSuperview];
lblCnt.hidden = YES;*/
for (UIView *view in [cell.contentView subviews])
{
if (view.tag == 1000)
{
[view removeFromSuperview];
}
}
}
return cell;
}
I am displaying contact name with a label in UITableView.The label displaying number of received messages for each contact.My view name is chatViewcontroller.If I am in that view that label count does not updated.For ex:For contact name "John" label count is "2".When John receives a message that label count should be updated as "3".It is not happening so.It is updated if i move come from another view.Is it possible to Update tableView chatviewController itself?.
Make sure that you updated your datasource(clist) and then call [tableview reloadData]
I have a tableview with the accessoryview of a toggle switch. I specify the section and the row and am having a difficult time determining which row was toggled. I used the toggleSwitch.tag to grab the indexRow but as my indexRow is part of an indexPath.section I am not sure how to tell which row I toggled.
Here is the code:
- (UITableViewCell *)tableAlert:(SBTableAlert *)tableAlert cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
Category *cat = [allCategories objectAtIndex:indexPath.section];
Subject *sub = [cat.subjects objectAtIndex:indexPath.row];
cell = [[[SBTableAlertCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
UISwitch *toggleSwitch = [[UISwitch alloc] init];
cell.accessoryView = [[UIView alloc] initWithFrame:toggleSwitch.frame];
[cell.accessoryView addSubview:toggleSwitch];
cell.textLabel.text =sub.title;
cell.detailTextLabel.text = sub.category_title;
if (sub.active==1){
[toggleSwitch setOn:YES];
} else {
[toggleSwitch setOn:NO];
}
toggleSwitch.tag = indexPath.row;
[toggleSwitch addTarget:self action:#selector(viewButtonPushed:) forControlEvents:UIControlEventValueChanged];
[toggleSwitch release];
return cell;
}
- (void)viewButtonPushed:(id)sender {
UIButton *button = (UIButton *)sender;
UITableViewCell *cell = button.superview; // adjust according to your UITableViewCell-subclass' view hierarchy
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
Category *cat = [allCategories objectAtIndex:indexPath.section];
Subject *sub = [cat.subjects objectAtIndex:indexPath.row];
selectedSubject = sub;
UISwitch* switchControl = sender;
NSLog( #"The switch is %#", switchControl.on ? #"ON" : #"OFF" );
if(switchControl.on){
[sub setActive:1];
NSLog(#"%# is being set to ACTIVE", selectedSubject.title);
}else{
[sub setActive:0];
NSLog(#"%# is being set to INACTIVE", selectedSubject.title);
}
[sub setIsDirty:YES];
[cat.subjects replaceObjectAtIndex:indexPath.row withObject:sub];
[sub autorelease];
[cat autorelease];
}
Here is my didSelectRowAtIndexPath. Do I need to have any reference to the toggleSwitch here?
- (void)tableAlert:(SBTableAlert *)tableAlert didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Category *cat = [allCategories objectAtIndex:indexPath.section];
Subject *sub = [cat.subjects objectAtIndex:indexPath.row];
selectedSubject = sub;
NSLog(#"selectedSubject = %#", selectedSubject.title);
if (tableAlert.type == SBTableAlertTypeMultipleSelct) {
UITableViewCell *cell = [tableAlert.tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone)
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
else
[cell setAccessoryType:UITableViewCellAccessoryNone];
[tableAlert.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
}
I have found that you need to go to the superview of the superview of the item in the cell (assuming that the button or control is right off the root of the cell) in order to get the pointer to the cell.
Try this instead:
UITableViewCell *cell = button.superview.superview;
and see if the results are any better. Check out my blog post on this for more information:
Two superviews are better than one
I have a TableViewController that is using a grouped Style and has two(2) sections. The first section has 4 rows and the second section has 3 rows. I have placed a UILabel and a UITextField in each cell, and have a custom method(textFieldDone:) to handle the cursor movement to the next text field when the return key is press.
This works fine and dandy if there is only one section, but I have two :( and yes I need two:)
so I started codin' up an answer, but got results that just don't work, I did notice during my debugging that cell Identifier (I use Two) is only showing the one (in the debug consol) and it's the first one only (Generic Cell).
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
switch (indexPath.section)
{
case AUTO_DETAILS:
{
static NSString *cellID = #"GenericCell";
cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2
reuseIdentifier:cellID] autorelease];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 75, 25)];
label.tag = kLabelTag;
label.font = [UIFont boldSystemFontOfSize:14];
label.textAlignment = UITextAlignmentRight;
[cell.contentView addSubview:label];
[label release];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(90, 12, 200, 25)];
textField.clearsOnBeginEditing = NO;
[textField setDelegate:self];
[textField addTarget:self action:#selector(topTextFieldDone:) forControlEvents:UIControlEventEditingDidEndOnExit];
[cell.contentView addSubview:textField];
}
NSInteger row = [indexPath row];
UILabel *label = (UILabel *)[cell viewWithTag:kLabelTag];
UITextField *textField = nil;
for (UIView *oneView in cell.contentView.subviews)
{
if ([oneView isMemberOfClass:[UITextField class]])
textField = (UITextField *)oneView;
}
label.text = [topCellLabels objectAtIndex:row];
NSNumber *rowAsNum = [[NSNumber alloc] initWithInt:row];
switch (row)
{
case kMakeRowIndex:
if ([[tempValues allKeys] containsObject:rowAsNum])
textField.text = [tempValues objectForKey:rowAsNum];
else
textField.text = automobile.make;
break;
case kModelRowIndex:
if ([[tempValues allKeys] containsObject:rowAsNum])
textField.text = [tempValues objectForKey:rowAsNum];
else
textField.text = automobile.model;
break;
case kYearRowIndex:
if ([[tempValues allKeys] containsObject:rowAsNum])
textField.text = [tempValues objectForKey:rowAsNum];
else
textField.text = automobile.year;
break;
case kNotesRowIndex:
if ([[tempValues allKeys] containsObject:rowAsNum])
textField.text = [tempValues objectForKey:rowAsNum];
else
textField.text = automobile.notes;
break;
default:
break;
}
if (textFieldBeingEdited == textField)
{
textFieldBeingEdited = nil;
}
textField.tag = row;
[rowAsNum release];
break;
}
case AUTO_REGISTRATION:
{
static NSString *AutoEditCellID = #"AutoEditCellID";
cell = [tableView dequeueReusableCellWithIdentifier:AutoEditCellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2
reuseIdentifier:AutoEditCellID] autorelease];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 75, 25)];
label.tag = kLabelTag;
label.font = [UIFont boldSystemFontOfSize:14];
label.textAlignment = UITextAlignmentRight;
[cell.contentView addSubview:label];
[label release];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(90, 12, 200, 25)];
textField.clearsOnBeginEditing = NO;
[textField setDelegate:self];
[textField addTarget:self action:#selector(bottomTextFieldDone:) forControlEvents:UIControlEventEditingDidEndOnExit];
[cell.contentView addSubview:textField];
}
NSInteger row = [indexPath row];
UILabel *label = (UILabel *)[cell viewWithTag:kLabelTag];
UITextField *textField = nil;
for (UIView *oneView in cell.contentView.subviews)
{
if ([oneView isMemberOfClass:[UITextField class]])
textField = (UITextField *)oneView;
}
label.text = [bottomCellLabels objectAtIndex:row];
NSNumber *rowAsNum = [[NSNumber alloc] initWithInt:row];
switch (row)
{
case 0:
if ([[tempValues allKeys] containsObject:rowAsNum])
textField.text = [tempValues objectForKey:rowAsNum];
else
textField.text = automobile.vinNumber;
break;
case 1:
if ([[tempValues allKeys] containsObject:rowAsNum])
textField.text = [tempValues objectForKey:rowAsNum];
else
textField.text = automobile.policyNumber;
break;
case 2:
if ([[tempValues allKeys] containsObject:rowAsNum])
textField.text = [tempValues objectForKey:rowAsNum];
else
textField.text = automobile.licensePlate;
break;
default:
break;
}
if (textFieldBeingEdited == textField)
{
textFieldBeingEdited = nil;
}
textField.tag = row;
[rowAsNum release];
break;
}
default:
break;
}
return cell;
}
Now remember that the first section is working fine and the code for that method is this:
-(IBAction)topTextFieldDone:(id)sender
{
UITableViewCell *cell = (UITableViewCell *)[[sender superview] superview];
UITableView *table = (UITableView *)[cell superview];
NSIndexPath *textFieldIndexPath = [table indexPathForCell:cell];
NSUInteger row = [textFieldIndexPath row];
row++;
if (row > kNumOfEditableRows)
row = 0;
NSUInteger newIndex[] = {0, row};
NSIndexPath *newPath = [[NSIndexPath alloc] initWithIndexes:newIndex length:2];
UITableViewCell *nextCell = [self.tableView cellForRowAtIndexPath:newPath];
UITextField *nextField = nil;
for (UIView *oneView in nextCell.contentView.subviews)
{
if ([oneView isMemberOfClass:[UITextField class]])
nextField = (UITextField *)oneView;
}
[nextField becomeFirstResponder];
}
It was my idea to just create a second method (secondSectionTextFieldDone:) like this
-(IBAction)bottomTextFieldDone:(id)sender
{
UITableViewCell *cell = (UITableViewCell *)[[sender superview] superview];
UITableView *table = (UITableView *)[cell superview];
NSIndexPath *textFieldIndexPath = [table indexPathForCell:cell];
NSUInteger row = [textFieldIndexPath row];
row++;
if (row > 3)
row = 0;
NSUInteger newIndex[] = {0, row};
NSIndexPath *newPath = [[NSIndexPath alloc] initWithIndexes:newIndex length:2];
UITableViewCell *nextCell = [self.tableView cellForRowAtIndexPath:newPath];
UITextField *nextField = nil;
NSString *string = [NSString stringWithFormat:#"AutoEditCellID"];
for (UIView *oneView in nextCell.contentView.subviews)
{
NSLog(#"%#", nextCell.reuseIdentifier); /* DEBUG LOG */
if ([oneView isMemberOfClass:[UITextField class]] && (nextCell.reuseIdentifier == string))
nextField = (UITextField *)oneView;
}
[nextField becomeFirstResponder];
}
but the result does not solve the issue.
so my question is, how can i get the cursor to jump to the next textfield in the section that it is in, If there is one, and if not, then send a message "resignFirstResponder" so that, the keyboard goes away.
implement UITextFieldDelegate
yourFirstTextFeld.delegate = self;
yourSecondTextFeld.delegate=self;
implement this method
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
if(theTextField==yourFirstTextFeld){
[yourSecondTextFeld becomeFirstResponder];
}
return YES;
}
I have three cells, within that I have each textfields. Now I want the user is clicking in which textbox. This method textFieldDidEndEditing gives me the value which user is inputting but I don't get any tag of the textfield.
Here is my code:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{ switch (section)
{ case 0: return #"";
case 1: return #"";
default:return #"";
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if(optconscodecount != 0 && gotOK == 2)
return 2;
else
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
switch(section)
{ case 0: try=1; return conscodecount;
case 1: try=2; return optconscodecount;
default:return 0;}
}
// Heights per row
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{ int section = [indexPath section];
//int row = [indexPath row];
switch (section)
{case 0:return 80.0f;
case 1:return 80.0f;
default:return 80.0f;}
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"\n%#", appDelegate.conscodeNameArray);
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
row = [indexPath row];
section = [indexPath section];
switch (section)
{case 0:try=1;cell = [tableView dequeueReusableCellWithIdentifier:#"textCell"];
if (!cell)
{cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"textCell"] autorelease];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 10.0f, 280.0f, 20.0f)];
[label setText:[appDelegate.conscodeNameArray objectAtIndex:row]];[cell addSubview:label]; [label release];
[cell addSubview:[[UITextField alloc] initWithFrame:CGRectMake(20.0f, 40.0f, 280.0f, 30.0f)]];
}
UITextField *tf = [[cell subviews] lastObject];
tf.placeholder = [appDelegate.conscodeNameArray objectAtIndex:row];
tf.tag =tagcount;
tagcount=tagcount+1;
tf.delegate = self;
tf.borderStyle = UITextBorderStyleRoundedRect;
return cell;
break;
case 1:
try=2;
cell = [tableView dequeueReusableCellWithIdentifier:#"textCell"];
if (!cell)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"textCell"] autorelease];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 10.0f, 280.0f, 20.0f)];
[label setText:[appDelegate.optconscodeNameArray objectAtIndex:row]];
[cell addSubview:label];
[label release];
[cell addSubview:[[UITextField alloc] initWithFrame:CGRectMake(20.0f, 40.0f, 280.0f, 30.0f)]];
}
UITextField *my = [[cell subviews] lastObject];
my.tag = 0;
my.tag = my.tag+1;
my.placeholder = [appDelegate.optconscodeNameArray objectAtIndex:row];
my.delegate = self;
my.borderStyle = UITextBorderStyleRoundedRect;
return cell;
break;
return cell;
break;
default:
break;
}
return cell;
}
nameField.tag = 1;
agefield.tag = 2;
// in the delegate method just check
if (textField.tag == 1) {
NSLog(#" clicked in Name field");
} else if (textField.tag ==2) {
NSLog(#" clicked in Age field");
}
If you were to retain each text field in an instance variable, you could do a simple comparison in your delegate method to see which field had finished editing. You can do this even if you create them completely dynamically by using an associative array to map from the instance to the field name, or vice-versa.