Weird Behaviour of cellForRow caused by UITextField - iphone

I have a TableView which has 2 sections and the 2nd section is only shown when the 3rd row in the first section is selected. Only the first section has images. Everything is working fine. The 3rd row in the 2nd section shows a TextField and a button when selected and you can save a date in there via pressing the finish button. Works also fine. You can select that row and go to other rows and everything is normal. If though, you tap into the TextField and don't save the input or don't write anything, then it bugs.
It will reload the table with images at random rows it seems.
I thought it's the keyboard which pops up, so I tried to manually dismiss it. Bug is still there.
I am really curious why this happens, so I am hoping for help! Thanks in advance!!
My cellForRowAtIndexPath:
- (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] autorelease];
}
// Configure the cell...
BOOL tooltipValue = [[NSUserDefaults standardUserDefaults] boolForKey:#"tooltipSetting"];
BOOL compactSettingValue = [[NSUserDefaults standardUserDefaults] boolForKey:#"compactModeSetting"];
NSDictionary *dictionary = [self.settingsArray objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"Items"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
if (indexPath.section == 0 && self.iconSetCount < 3) {
NSDictionary *imagedictionary = [self.imagesArray objectAtIndex:indexPath.section];
UIImage *cellImage = [[imagedictionary objectForKey:#"images"] objectAtIndex:indexPath.row];
cell.imageView.image = cellImage;
self.iconSetCount++;
NSLog(#"%d",self.iconSetCount);
}
if (indexPath.section == 0){
if (indexPath.row == 0) {
if (tooltipValue){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
if (indexPath.row == 1) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (indexPath.row == 2) {
if (!compactSettingValue){
cell.accessoryType = UITableViewCellAccessoryNone;
} else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
} else if (indexPath.section == 1){
// if the sellected row is the one with a custom date
if (indexPath.row == 2 && indexPath.row == isSelected) {
// if an archive exists for the custom date then get the data from the archive
if ([[NSFileManager defaultManager] fileExistsAtPath:[self getDocumentPathForCustomDate]]) {
NSString *customDate = [NSKeyedUnarchiver unarchiveObjectWithFile:[self getDocumentPathForCustomDate]];
cell.textLabel.text = customDate;
} else{
//show a label with a done button where you can type in your custom date and save it
if (self.textField == nil) {
self.textField = [[UITextField alloc] initWithFrame:CGRectMake(5, 5, 200, 35)];
self.textField.backgroundColor = [UIColor whiteColor];
self.textField.textColor = [UIColor blackColor];
self.textField.font = [UIFont systemFontOfSize:16.0];
self.textField.borderStyle = UITextBorderStyleRoundedRect;
}
if (self.button == nil) {
self.button =[UIButton buttonWithType:UIButtonTypeRoundedRect];
self.button.frame = CGRectMake(210, 5, 50, 35);
[self.button setTitle:NSLocalizedString(#"done", #"") forState:UIControlStateNormal];
[self.button addTarget:self action:#selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside];
}
[cell.contentView addSubview: self.textField];
[cell.contentView addSubview: self.button];
}
}
if ((indexPath.row == self.isSelected)){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
return cell;
}
My didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"Nib name" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
BOOL tooltipValue = [[NSUserDefaults standardUserDefaults] boolForKey:#"tooltipSetting"];
BOOL compactSettingValue = [[NSUserDefaults standardUserDefaults] boolForKey:#"compactModeSetting"];
if (indexPath.section == 0) {
//tooltips
if (indexPath.row == 0) {
if (!tooltipValue){
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"tooltipSetting"];
} else {
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"tooltipSetting"];
}
[self.tableView reloadData];
}
//go to Set your Signature Extra
if (indexPath.row == 1) {
AdditionalSignature *additionalSigi = [[AdditionalSignature alloc] initWithNibName:#"additionalSignature" bundle:nil];
[self.navigationController pushViewController:additionalSigi animated:YES];
[additionalSigi release];
}
//compact version
if (indexPath.row == 2) {
if (!compactSettingValue){
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"compactModeSetting"];
} else {
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"compactModeSetting"];
}
[self.tableView reloadData];
}
}
// if in optional compactmode settings
if (indexPath.section == 1){
// and "none" is selected remove first the custom date
if (indexPath.row == 0) {
[self removeCustomDateArchive];
//then change the userdefault for this setting
if (![self isOptionNoDate]) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"dateSetting"];
}else{
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"dateSetting"];
}
}
if ( indexPath.row == 1) {
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"dateSetting"];
[self removeCustomDateArchive];
}
if (indexPath.row == 2) {
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"dateSetting"];
}
self.isSelected = indexPath.row;
[self.tableView reloadData];
}
}

The cell identifier is abused here. Removing the cell identifier would be the quickest solution here, reallocating the cells every time.
Rewriting the code to include the cell identifier would make it more robust.

Related

How to set checkbox image while selecting table view section?

I'm working on a project and i stuck at a point. My project has a Table View with some data after clicking on the cell table view will expended into sections. Every thing is fine except one thing i.e i want to set a checkbox image (when the user clicked on a cell).
when i tap on the cell it gives the cell title text but i am not able to set the checkbox image (like UITableViewCellAccessoryCheckmark)on particular cell section.
I am posting the images and the codes below: !
MyTableView it contains the Root Exercise Names
This is the Expended View and i want a checkbox(UITableViewCellAccessoryCheckmark) at the right side of the cell.
When i click on tableView didSelectRowAtIndexPath: it works fine
//code
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) {
if ([indexPath isEqual:self.selectIndex]) {
self.isOpen = NO;
[self didSelectCellRowFirstDo:NO nextDo:NO];
self.selectIndex = nil;
}else
{
if (!self.selectIndex) {
self.selectIndex = indexPath;
[self didSelectCellRowFirstDo:YES nextDo:NO];
}else
{
[self didSelectCellRowFirstDo:NO nextDo:YES];
}
}
}else
{
NSDictionary *dic = [dataList objectAtIndex:indexPath.section];
NSArray *list = [dic objectForKey:#"ExcerciseList"]; //from plist
NSString *item = [list objectAtIndex:indexPath.row-1];
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
if (thisCell.accessoryType == UITableViewCellAccessoryNone)
{
thisCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
thisCell.accessoryType = UITableViewCellAccessoryNone;
}
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:item message:nil delegate:nil cancelButtonTitle:#"ok" otherButtonTitles: nil] ;
[alert show];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark- Table View DataSource and Delegates
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.isOpen&&self.selectIndex.section == indexPath.section&&indexPath.row!=0) {
static NSString *CellIdentifier = #"Cell1";
_cell = (Cell1*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!_cell) {
_cell = [[[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil] objectAtIndex:0];
//[[[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil] objectAtIndex:0];
}
NSArray *list = [[dataList objectAtIndex:self.selectIndex.section] objectForKey:#"ExcerciseList"];
_cell.titleLabel.text = [list objectAtIndex:indexPath.row-1];
//[_cell changecheckboxWithUp:([self.selectIndex isEqual:indexPath]?YES:NO)];
return _cell;
}
else
{
static NSString *CellIdentifier = #"view_TableView_List";
cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell=[[CustomCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSString *name = [[dataList objectAtIndex:indexPath.section] objectForKey:#"Excercise_Name"];
cell.Lbl_Excercise_Name.text = name;
cell.Lbl_Excercise_Name.font=[UIFont fontWithName:#"Hustlers Rough Demo" size:40.0f];
NSString *ImageName=[[dataList objectAtIndex:indexPath.section] objectForKey:#"Excercise_Image"];
[cell.imageView_Excercise_Image setImage:[UIImage imageNamed:ImageName]];
[cell changeArrowWithUp:([self.selectIndex isEqual:indexPath]?YES:NO)];
return cell;
}
}
My Question is How to show Checkbox at the selected section?
Sorry! if it is not formatted properly(New to stack)!
Thank You!
I was finally able to get it working. Here's what you have to change:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.isOpen&&self.selectIndex.section == indexPath.section&&indexPath.row!=0) {
static NSString *CellIdentifier = #"Cell1";
_cell = (Cell1*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!_cell) {
_cell = [[[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil] objectAtIndex:0];
//[[[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil] objectAtIndex:0];
}
NSArray *list = [[dataList objectAtIndex:self.selectIndex.section] objectForKey:#"ExcerciseList"];
_cell.titleLabel.text = [list objectAtIndex:indexPath.row-1];
_cell.accessoryView = nil;
if ([self.selectedCells containsObject:indexPath])
{
_cell.accessoryView = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"check_box#2x.png"]];
}
//[_cell changecheckboxWithUp:([self.selectIndex isEqual:indexPath]?YES:NO)];
return _cell;
}
else
{
static NSString *CellIdentifier = #"view_TableView_List";
cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell=[[CustomCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSString *name = [[dataList objectAtIndex:indexPath.section] objectForKey:#"Excercise_Name"];
cell.Lbl_Excercise_Name.text = name;
cell.Lbl_Excercise_Name.font=[UIFont fontWithName:#"Hustlers Rough Demo" size:40.0f];
NSString *ImageName=[[dataList objectAtIndex:indexPath.section] objectForKey:#"Excercise_Image"];
[cell.imageView_Excercise_Image setImage:[UIImage imageNamed:ImageName]];
[cell changeArrowWithUp:([self.selectIndex isEqual:indexPath]?YES:NO)];
return cell;
}
}
And
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) {
if ([indexPath isEqual:self.selectIndex]) {
self.isOpen = NO;
[self didSelectCellRowFirstDo:NO nextDo:NO];
self.selectIndex = nil;
}else
{
if (!self.selectIndex) {
self.selectIndex = indexPath;
[self didSelectCellRowFirstDo:YES nextDo:NO];
}else
{
[self didSelectCellRowFirstDo:NO nextDo:YES];
}
}
}else
{
NSDictionary *dic = [dataList objectAtIndex:indexPath.section];
NSArray *list = [dic objectForKey:#"ExcerciseList"];
NSString *item = [list objectAtIndex:indexPath.row-1];
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
if (!thisCell.accessoryView)
{
[self.selectedCells addObject:indexPath];
thisCell.accessoryView = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"check_box#2x.png"]];
}
else
{
[self.selectedCells removeObject:indexPath];
thisCell.accessoryView = nil;
}
// UIAlertView *alert = [[UIAlertView alloc] initWithTitle:item message:nil delegate:nil cancelButtonTitle:#"ok" otherButtonTitles: nil] ;
// [alert show];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
If nothing else has changed in those methods, just copy-paste the code and it will work. I tested it before posting it. Let me know if you have more questions
UPDATE
Here is the explanation of what was going on. There were actually a couple of problems:
First, you were mixing accessoryType and accessoryView; this was causing an
incorrect execution of the if-else clause. Here is the old code
// here you are using accessoryType
if (thisCell.accessoryType == UITableViewCellAccessoryNone)
{
// but here you're using accessoryView
thisCell.accessoryView = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"check_box#2x.png"]];
}
else
{
// here too...
thisCell.accessoryView=nil;
thisCell.accessoryView = nil;
}
Second, you were not saving the indexPaths of the selected elements. Here is the corrected code (note is the same if-else clause):
if (!thisCell.accessoryView)
{
// you have to save the selected indexPaths
[self.selectedCells addObject:indexPath];
thisCell.accessoryView = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"check_box#2x.png"]];
}
else
{
// if the cell was already selected, then remove the indexPath
[self.selectedCells removeObject:indexPath];
thisCell.accessoryView = nil;
}
Third, the following line inside of cellForRowAtIndexPath... was messing up things because it was showing another checkmark, so I just removed it:
[_cell.checkUnCheck_ImageView setHidden:NO];
That was pretty much it.
Hope this helps!
You have the right idea of how to do this, however, you're setting the checkmark in the wrong place. You should use the method -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath to store (remember) which cell was selected and NOT to set the accessory type.
If only one cell can be selected at a time you can declare aNSIndexPath property to remember the cell that was selected. However, if multiple cells can be selected at a time you can declare a NSMutableArray where you can store all the cells that have been selected.
Then you should use the method -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath to set the checkmark to the cells that were selected.
Here is an example (I'm assuming multiple cells can be selected):
In your *.h file declare a NSMutableArray property
#property (nonatomic, strong) NSMutableArray *selectedCells;
In your *.m file, inside your init method initialize the property:
_selectedCells = [[NSMutableArray alloc] init];
Then, in the didSelectRowAtIndexPath... method:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self.selectedCells containsObject:indexPath]) {
[self.selectedCells removeObject:indexPath]; // this line allows the checkmark to be shown/hidden if the user presses several times the same cell
} else {
[self.selectedCells addObject:indexPath]; // a cell was selected; remember it
}
... // the rest of your code
}
Finally, in the cellForRowAtIndexPath... method
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
... // Create, initialize and customize your cell
// if the cell you're being asked for is saved in the array it means it was selected
if ([self.selectedCells containsObject:indexPath]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
}
And that's it. Let me know if you have more questions
Hope it helps!
UPDATE
If all you want to do is to set a custom image as your checkmark just create the image and assign it to the accessory view while using the code that was already working for you, like so:
// Note that you should use 'accessoryView' and NOT 'accessoryType'
if (thisCell.accessoryView == UITableViewCellAccessoryNone)
{
thisCell.accessoryView = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"YOUR_IMAGE_NAME"]];
}
else
{
thisCell.accessoryView = nil;
}

TableView isn't updating data even though it recognizes input?

So I have 5 rows and on selection they pass an integer with the row number to my second view controller.
Each number has its own array with items and should then return the amount of items for the row specified.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MasterCell";
MasterCell *cell = (MasterCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
if (radInt == 0) {
cell.textLabel.text = #"LM";
NSLog(#"My return should have been LM");
}
if (radInt == 1) {
cell.textLabel.text = #"Restauranger";
NSLog(#"My return should have been Rest");
}
if (radInt == 2) {
cell.textLabel.text = [shoppingArray objectAtIndex:indexPath.row];
}
if (radInt == 3) {
cell.textLabel.text = [annatArray objectAtIndex:indexPath.row];
}
//cell.textLabel.text = [listData objectAtIndex:[indexPath row]];
cell.imageView.image = [UIImage imageNamed:#"tab-icon1.png"];
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
}
This is my code just to test it out and it doesn't work. NSLOG works correctly but the data simply wount update... What have I done wrong? It Nslogs LM every time but it also has 1 in the log which is the selected row (radInt).
New approach
static NSString *CellIdentifier = #"MasterCell";
MasterCell *cell = (MasterCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil)
cell = [[MasterCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
if (radInt == 0) {
cell.textLabel.text = #"LM";
NSLog(#"My return should have been LM");
}
else if (radInt == 1) {
cell.textLabel.text = #"Restauranger";
NSLog(#"My return should have been Rest");
}
else if (radInt == 2) {
cell.textLabel.text = [shoppingArray objectAtIndex:indexPath.row];
}
else if (radInt == 3) {
cell.textLabel.text = [annatArray objectAtIndex:indexPath.row];
}
else {
cell.textLabel.text = #"Noes";
}
//cell.textLabel.text = [listData objectAtIndex:[indexPath row]];
cell.imageView.image = [UIImage imageNamed:#"tab-icon1.png"];
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
The view before ----
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
SecondViewController *enjoy = [[SecondViewController alloc] init];
if ([[array objectAtIndex:indexPath.row] isEqual:#"Livsmedel"]) {
[enjoy setTitle:[array objectAtIndex:indexPath.row]];
enjoy.radInt = 0;
NSLog(#"0");
}
if ([[array objectAtIndex:indexPath.row] isEqual:#"Restauranger"]) {
[enjoy setTitle:[array objectAtIndex:indexPath.row]];
enjoy.radInt = 1;
NSLog(#"1");
}
if ([[array objectAtIndex:indexPath.row] isEqual:#"Shopping"]) {
[enjoy setTitle:[array objectAtIndex:indexPath.row]];
enjoy.radInt = 2;
}
if ([[array objectAtIndex:indexPath.row] isEqual:#"Annat"]) {
enjoy.radInt = 3;
}
[self performSegueWithIdentifier:#"main" sender:self];
}
You don't actually need to implement didSelectRowAtIndexPath: if you connect the segue in the storyboard from the cell to the next controller. What you need to implement is prepareForSegue:. Your code should look something like this:
- (void)prepareForSegue:(UIStoryboardSegue *) segue sender:(id) sender
{
NSInteger row = [self.tableView indexPathForSelectedRow].row;
SecondViewController *enjoy = segue.destinationViewController;
if ([[array objectAtIndex:row] isEqual:#"Livsmedel"]) {
[enjoy setTitle:[array objectAtIndex:row]];
enjoy.radInt = 0;
NSLog(#"0");
}
if ([[array objectAtIndex:row] isEqual:#"Restauranger"]) {
[enjoy setTitle:[array objectAtIndex:row]];
enjoy.radInt = 1;
NSLog(#"1");
}
if ([[array objectAtIndex:row] isEqual:#"Shopping"]) {
[enjoy setTitle:[array objectAtIndex:row]];
enjoy.radInt = 2;
}
if ([[array objectAtIndex:row] isEqual:#"Annat"]) {
enjoy.radInt = 3;
}
}

Keeping a track of selected cells

In my app, the user changes the fields that appear in a tableView depending on the cells selected by him/her. (FYI... I have permitted multiple cell selection.) Just when the user presses the back button, the program copies the textLabel of the selected cells to the placeholder of the parent viewController.
Here's the relevant section of my code:
- (void)willMoveToParentViewController:(UIViewController *)parent
{
int tempCount = 0;
for (int section = 0; section < 3; section++)
{
int rowMax;
if (section == 0)
rowMax = 3;
else if (section == 1)
rowMax = 5;
else if(section == 2)
rowMax = 3;
for(int row = 0; row < rowMax; row++)
{
NSIndexPath *tempIndexPath = [NSIndexPath indexPathForRow:row inSection:section];
UITableViewCell *selectedCell = [self.tableView cellForRowAtIndexPath:tempIndexPath];
if(selectedCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
NSLog(#"tempCount = %d", tempCount);
tempCount++;
if (tempCount == 1)
chosenFieldsViewController.field0.placeholder = selectedCell.textLabel.text;
else if(tempCount == 2)
chosenFieldsViewController.field1.placeholder = selectedCell.textLabel.text;
else if(tempCount == 3)
chosenFieldsViewController.field2.placeholder = selectedCell.textLabel.text;
}
}
}
}
I realized that after selecting the cells if the tableView is scrolled down, the selected cells do not appear as placeHolder on the parentVC. From my analysis I think that once I scroll down, the cells are deleted from the memory. So despite the fact that the cells are selected, they fail to show up on the parent VC.
If so, why do I see the cells appear selected when I scroll up?
I would be grateful if somebody can suggest how I can keep a track of the selected cells even when the user scrolls.
Thanks.
Edit 1
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if(selectedCell.accessoryType != UITableViewCellAccessoryCheckmark && count<3)
{
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
count ++;
}
else if(selectedCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
selectedCell.accessoryType = UITableViewCellAccessoryNone;
count--;
}
}
Edit 2
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"CellForRow%dSection%d",indexPath.row, indexPath.section];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone; // VERY IMPORTANT
if (indexPath.section == 0)
{
switch(indexPath.row)
{
case 0:
cell.textLabel.text = #"Class A";
break;
case 1:
cell.textLabel.text = #"Class B";
break;
case 2:
cell.textLabel.text = #"Class C";
break;
default:
break;
}
}
if(indexPath.section == 1)
{
switch(indexPath.row)
{
case 0:
cell.textLabel.text = #"Class D";
break;
case 1:
cell.textLabel.text = #"Class E";
break;
case 2:
cell.textLabel.text = #"Class F";
break;
case 3:
cell.textLabel.text = #"Class G";
break;
case 4:
cell.textLabel.text = #"Class H";
break;
default:
break;
}
}
if(indexPath.section == 2)
{
switch (indexPath.row)
{
case 0:
cell.textLabel.text = #"Class I";
break;
case 1:
cell.textLabel.text = #"Class J";
break;
case 2:
cell.textLabel.text = #"Class K";
break;
default:
break;
}
}
return cell;
}
Declare a dictionary as,
#property (nonatomic, retain) NSMutableDictionary *selectedTextListDict;
In viewDidLoad,
NSMutableDictionary *selectedTextListDict = [[NSMutableDictionary alloc] init];
Then change these methods as,
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if(selectedCell.accessoryType != UITableViewCellAccessoryCheckmark && count < 3)
{
NSString *rowKeyString = [NSString stringWithFormat:#"%d", indexPath.row];
NSString *sectionKeyString = [NSString stringWithFormat:#"%d", indexPath.section];
NSMutableDictionary *row = [self.selectedTextListDict valueForKey:sectionKeyString];
if (!row) {
row = [[NSMutableDictionary alloc] init];
}
[row setObject:selectedCell.textLabel.text forKey:rowKeyString];
[self.selectedTextListDict setObject:row forKey:sectionKeyString];
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
count ++;
}
else if(selectedCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
NSString *rowKeyString = [NSString stringWithFormat:#"%d", indexPath.row];
NSString *sectionKeyString = [NSString stringWithFormat:#"%d", indexPath.section];
NSMutableDictionary *row = [self.selectedTextListDict valueForKey:sectionKeyString];
[row removeObjectForKey:rowKeyString];
if ([[row allKeys] count] == 0) {
[self.selectedTextListDict removeObjectForKey:sectionKeyString];
} else {
[self.selectedTextListDict setObject:row forKey:sectionKeyString];
}
selectedCell.accessoryType = UITableViewCellAccessoryNone;
count--;
}
}
- (void)willMoveToParentViewController:(UIViewController *)parent
{
NSArray *selectedTextSectionKeysList = [self.selectedTextListDict allKeys];
NSArray *sortedSelectedTextSectionKeysList = [selectedTextSectionKeysList sortedArrayUsingSelector:#selector(intValue)];
int tempCount = 0;
for (NSString *sectionString in sortedSelectedTextSectionKeysList) {
NSMutableDictionary *rowDict = [self.selectedTextListDict valueForKey:sectionString];
if (rowDict) {
NSArray *selectedTextRowKeysList = [rowDict allKeys];
NSArray *sortedSelectedTextRowKeysList = [selectedTextRowKeysList sortedArrayUsingSelector:#selector(intValue)];
for (NSString *rowString in sortedSelectedTextRowKeysList) {
tempCount++;
if (tempCount == 1)
chosenFieldsViewController.field0.placeholder = [rowDict valueForKey:rowString];
else if(tempCount == 2)
chosenFieldsViewController.field1.placeholder = [rowDict valueForKey:rowString];
else if(tempCount == 3)
chosenFieldsViewController.field2.placeholder = [rowDict valueForKey:rowString];
}
}
}
}
Edit 1:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"GoToModifyFieldsViewController"])
{
ModifyFieldsViewController *modifyFieldsViewController = segue.destinationViewController;
modifyFieldsViewController.chosenFieldsViewController = self;
field0.placeholder = #"";
field1.placeholder = #"";
field2.placeholder = #"";
if(self.selectedTextListDict)
self.selectedTextListDict = [[NSMutableDictionary alloc] init];
}
}
Declare a dictionary in ChosenFieldsViewController: as,
#property (nonatomic, retain) NSMutableDictionary *selectedTextListDict;
In viewDidLoad,
selectedTextListDict = [[NSMutableDictionary alloc] init];
Therefore, rather using self.selectedTextListDict, use: chosenFieldsViewController.selectedTextListDict in ModifyFieldsViewController.
-If so, why do I see the cells appear selected when I scroll up?
Because they get created automatically whenever they are about to appear. Every time you scroll up or down, cells get created or reused. When they disappear, they get destroyed or marked for reuse.

Set switch to On, reload table then insert a new row

I've got an UITableViewController that I use to create settings of my application.
There is a section with only one row where I put an UISwitch.
How can I insert a new row inside the same section of row with the switch only if the switch in set to YES? And how can I delete this row if the switch is set to NO?
Can anyone help me? Thanks!
I tried to use insertRowsAtIndexPaths:withRowAnimation: method but doesn't work...
This is my settings table code:
- (void)viewDidLoad {
[super viewDidLoad];
self.title = NSLocalizedString(#"Impostazioni", #"");
}
- (void)viewWillAppear:(BOOL)animated {
[self.tableView reloadData];
}
-(void)addCellToSetCode:(id)sender {
if ([codeSwitch isOn]) {
NSIndexPath *updatedIndexPath = [NSIndexPath indexPathForRow:1 inSection:2];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:updatedIndexPath] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
[[NSUserDefaults standardUserDefaults] setBool:codeSwitch.on forKey:#"stateOfSwitch"];
}
else {
NSIndexPath *updatedIndexPath = [NSIndexPath indexPathForRow:1 inSection:2];
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:updatedIndexPath] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
[[NSUserDefaults standardUserDefaults] setBool:codeSwitch.on forKey:#"stateOfSwitch"];
}
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 4;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (section == 0) {
return NSLocalizedString(#"ListaDesideri", #"");
}
if (section == 1) {
return NSLocalizedString(#"CondivisioneMail", #"");
}
if (section == 2) {
return #"Sicurezza";
}
else {
return nil;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) || (section == 2) || (section == 3) {
return 2;
}
else if (section == 1) {
return 1;
}
else {
return 1;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
if (indexPath.section == 0 && indexPath.row == 0) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
cell.textLabel.text = NSLocalizedString(#"Ordine", #"");
if ([[defaults objectForKey:#"ordinaPer"] isEqualToString:#"Nome"]) {
cell.detailTextLabel.text = NSLocalizedString(#"Nome", #"");
}
if ([[defaults objectForKey:#"ordinaPer"] isEqualToString:#"Costo"]) {
cell.detailTextLabel.text = NSLocalizedString(#"Costo", #"");
}
if ([[defaults objectForKey:#"ordinaPer"] isEqualToString:#"Categoria"]) {
cell.detailTextLabel.text = NSLocalizedString(#"Categoria", #"");
}
if ([[defaults objectForKey:#"ordinaPer"] isEqualToString:#"Nome Discendente"]) {
cell.detailTextLabel.text = NSLocalizedString(#"NomeDiscendente", #"");
}
if ([[defaults objectForKey:#"ordinaPer"] isEqualToString:#"Costo Discendente"]) {
cell.detailTextLabel.text = NSLocalizedString(#"CostoDiscendente", #"");
}
if ([[defaults objectForKey:#"ordinaPer"] isEqualToString:#"Categoria Discndente"]) {
cell.detailTextLabel.text = NSLocalizedString(#"CategoriaDiscendente", #"");
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (indexPath.section == 0 && indexPath.row == 1) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
cell.textLabel.text = NSLocalizedString(#"DettagliDesiderio", #"");
if ([[defaults objectForKey:#"dettagliView"] isEqualToString:#"costoView"]) {
cell.detailTextLabel.text = NSLocalizedString(#"Costo", #"");
}
if ([[defaults objectForKey:#"dettagliView"] isEqualToString:#"descrizioneView"]) {
cell.detailTextLabel.text = NSLocalizedString(#"Descrizione", #"");
}
if ([[defaults objectForKey:#"dettagliView"] isEqualToString:#"urlView"]) {
cell.detailTextLabel.text = NSLocalizedString(#"URL", #"");
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (indexPath.section == 1 && indexPath.row == 0) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
cell.textLabel.text = NSLocalizedString(#"Shortener", #"");
if ([[defaults objectForKey:#"linkShortener"] isEqualToString:#"Nessuno"]) {
cell.detailTextLabel.text = NSLocalizedString(#"Nessuno", #"");
}
if ([[defaults objectForKey:#"linkShortener"] isEqualToString:#"is.gd"]) {
cell.detailTextLabel.text = NSLocalizedString(#"is.gd", #"");
}
if ([[defaults objectForKey:#"linkShortener"] isEqualToString:#"bit.ly"]) {
cell.detailTextLabel.text = NSLocalizedString(#"bit.ly", #"");
}
if ([[defaults objectForKey:#"linkShortener"] isEqualToString:#"TinyURL"]) {
cell.detailTextLabel.text = NSLocalizedString(#"TinyURL", #"");
}
if ([[defaults objectForKey:#"linkShortener"] isEqualToString:#"Linkyy"]) {
cell.detailTextLabel.text = NSLocalizedString(#"Linkyy", #"");
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (indexPath.section == 2 && indexPath.row == 0) {
cell.textLabel.text = #"Access Code";
codeSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 84, 27)];
cell.accessoryView = codeSwitch;
[codeSwitch addTarget:self action:#selector(addCellToSetCode:) forControlEvents:UIControlEventValueChanged];
codeSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:#"codeSwitchState"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
if (indexPath.section == 3 && indexPath.row == 0) {
cell.textLabel.text = NSLocalizedString(#"Supporto", #"");
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if (indexPath.section == 3 && indexPath.row == 1) {
cell.textLabel.text = NSLocalizedString(#"Informazioni", #"");
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}
EDIT: Updates below...
I solved part of this problem!
I tried to use [self.tableView reloadData] but doesn't work and casually I solved using [self.tableView setNeedsDisplay]...
Now the switch works but if I set to On it and then I go out from app, completely closing it, the switch doesn't work... How can I solve this?
If this can help other, these are pieces of code updated:
-(void)addCellToSetCode:(id)sender {
if ([codeSwitch isOn]) {
NSIndexPath *updatedIndexPath = [NSIndexPath indexPathForRow:1 inSection:2];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:updatedIndexPath] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
[self.tableView setNeedsDisplay];
[[NSUserDefaults standardUserDefaults] setBool:codeSwitch.on forKey:#"codeSwitchState"];
}
else {
NSIndexPath *updatedIndexPath = [NSIndexPath indexPathForRow:1 inSection:2];
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:updatedIndexPath] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
[self.tableView setNeedsDisplay];
[[NSUserDefaults standardUserDefaults] setBool:codeSwitch.on forKey:#"codeSwitchState"];
}
}
// tableView:numberOfRowsInSection:
else if (section == 2) {
return codeSwitch.on ? 2 : 1;
}
// tableView:cellForRowAtIndexPath:
if (indexPath.section == 2 && indexPath.row == 0) {
cell.textLabel.text = #"Access Code";
codeSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 84, 27)];
cell.accessoryView = codeSwitch;
[codeSwitch addTarget:self action:#selector(addCellToSetCode:) forControlEvents:UIControlEventValueChanged];
codeSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:#"codeSwitchState"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
if (indexPath.section == 2 && indexPath.row == 1) {
if ([codeSwitch isOn]) {
cell.textLabel.text = #"Set Access Code";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
At least part of your problem (in the updated code) is that you don't create the UISwitch until you create the cell. Your codeSwitch ivar may end up pointing to a different switch as that table row comes in and out of view.
Here's how I'd do this: in tableView:numberOfRowsInSection:, use the NSUserDefaults to see which state the table should be in, instead of using the state of the switch (which may not exist yet). Then, in the switch's action method, call setBool:forKey: for the user defaults before you insert or delete the table row.
In essence, this makes the code follow the MVC model better, because it separates your view (the UISwitch) from the model (the BOOL in user defaults), with the controller (the view controller) in the middle. By confounding the view and the model (the switch and the boolean state), you end up with problems when trying to deal with the state when the view isn't available yet.
BTW, you shouldn't need to call setNeedsDisplay on the table view at all.

My tableView only refresh from the UISearchBar only after an additional character is added

I have a tableView that refreshes with data from an array via the textDidChange function for UISearchBar. The data is correct, but it does not appear in the tableView until after hitting an additional character (so, for instance, if i typed 'Boise' into the search bar, nothing happens, but 'Boise1' will load two cities named 'Boise'..so it's one step behind).
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
//---if there is something to search for---
if ([searchText length] > 0) {
NSLog(#"greater than 0!");
isSearchOn = YES;
canSelectRow = YES;
self.tableView.scrollEnabled = YES;
[self performSelector:#selector(someMethod) withObject:nil afterDelay:0];
//[NSThread detachNewThreadSelector:#selector(matchSearchText)
// toTarget:self withObject:nil];
//[self matchSearchText];
}
else {
//---nothing to search---
isSearchOn = NO;
canSelectRow = NO;
self.tableView.scrollEnabled = NO;
}
}
and in the method that is called:
- (void) someMethod {
NSLog(#"-------------");
NSLog(#"some Method whut!");
CityLookup *cityLookup = [[CityLookup alloc] findCity:searchBar.text];
// clear array
[tableCities removeAllObjects];
if ([cityLookup.citiesList count] > 0) {
tableCities = cityLookup.citiesList;
int size = [tableCities count];
NSLog(#"there are %d objects in the array", size);
}
[cityLookup release];
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:tableCities waitUntilDone:YES];
}
and finally the cellForRowAtIndexPath:
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
int size = [tableCities count];
NSLog(#"there are %d objects in the array NOW", size);
static NSString *kCellID = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
NSString *cellValue = [tableCities objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
return cell;
}