Checkmark rows in searchResultsTableView - ios

I have a tableView who's datasource is an array with 400 static items in it. In my app you can select a row and it will place a checkmark on that row. I'm keeping track of the checked item's indexPaths in another array so that the table can be reloaded later and those items will still be checked.
Since my table has a lot of values in it I've added a searchDisplayController. Start typing what your looking for and it'll filter the list down to those items. You can select rows in the searchResultsTableView and it will check them, just like in the main table with the 400 static rows. However, there's a problem:
Let's say you enter a search and narrow the list of 400 items down to the one you're looking for and you select (checkmark) it. In the full list of 400 items, the one you just searched for might be number 112 in the list, however when you did your search and filtered down to only that one item, instead of adding the indexPath of item 112 to my array that keeps track, it entered the indexPath of item 0 because it was the only item showing in the filtered list.
So when you cancel out of search and go back to the main list instead of their being a checkmark on item 112, there's a checkmark on item 0.
So I'm looking for a way to keep my filtered array in sync with my main tableView datasource.
The relevant bit of my didSelectRowAtIndexPath method:
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [filteredattributesArray objectAtIndex:[indexPath row]];
if(cell.accessoryType == UITableViewCellAccessoryNone){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[selectedItemRows addObject:indexPath]; //Add the index path of checked cell into array to keep track
[tableView reloadData];
} else {
if(cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
[selectedItemRows removeObject:indexPath]; //Remove that index path of unchecked cell from index array
[tableView reloadData];
}
}
[tableView deselectRowAtIndexPath:indexPath animated:YES]; }
}

Don't use indexPath. Set the tag value on each item in your data array and then keep a list of tags for your "checkedArray". That way you can evaluate the checked items independent of the cells or tableView structure.

Related

Capture the index value of a cell but only from the visible cells on the screen

I am trying to trigger some code based on if the cell I selected becomes the first or last cell on the users screen. I'm not trying to capture the index value of the data array. Just the index value of the cell that is visible on the screen. I'm sure this to create an array of visible cells.
NSArray *indexPathsForVisibleRows = [myTableView
indexPathsForVisibleRows];
But I keep hitting a dead end trying to then capture an index value based on that array.
I tried to use a CGPoint and convert that, but I keep getting an error. Any insight would be most helpful!
As per the documentation for the return value of that method:
An array of NSIndexPath objects each representing a row
index and section index that together identify a visible row in the
table view. Returns nil if no rows are visible.
The array returned from that method contains NSIndexPaths.
NSArray *indexPathsForVisibleRows = [myTableView indexPathsForVisibleRows];
for(NSIndexPath *eachIndexPath in indexPathsForVisibleRows)
{
NSInteger row = eachIndexPath.row;
NSInteger section = eachIndexPath.section;
UITableViewCell *cell = [myTableView cellForRowAtIndexPath:eachIndexPath];
if(cell.isSelected)
{
// this is our selected cell
}
}

Deselect invisible row

I have problem with updating rows in UITableView. In my tableView only one row in section can be selected (there can be a couple of section). So, when user select row, I programmatically deselect other rows in this section. Everything works when deselected rows are visible. If any deselected row isn't visible, then it is still checked. But didDeselectRowAtIndexPath is called for this row. Why? How to fix this?
- (NSIndexPath*)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
// It is predefined group - only one row in section cab be selected
// Deselect other rows in section
for (NSIndexPath * selectedIndexPath in tagTableView.indexPathsForSelectedRows) {
if (selectedIndexPath.section == indexPath.section) {
[self tableView:tableView didDeselectRowAtIndexPath:selectedIndexPath];
[tableView deselectRowAtIndexPath:selectedIndexPath animated:YES];
}
}
return indexPath;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tagTableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
Selected state of a cell should not saved in the UITableViewCell but in the object (model) that fills the cell.
Since tablecells are reused there state are representing the the last state of the model that filled them. You should either keep the selected state in the object filling the cell of keep an array of select indexPaths.
The in the -tableView:cellForRowAtIndexPath: set the correct state of that cell. If you model object hold the selected state you can just set the state according to that property or if you are keeping an array with select indexpaths check if the path is in the array and set the state accordingly.

core data saving in textboxes in table view controller

I have created a five column (text boxes) cell (row) in table view controller with an option of add button. When a user clicks on add button, a new row (cell) with five column (text boxe) is added in a table view controller with null values. I want that when user fills the text boxes the data should get saved in database or if he changes any data in previous text boxes also it get saved.
this is my save btn coding..
- (IBAction)btn_save:(id)sender
{
NSInteger noOfRow=[(NSSet *)[projectObject valueForKey:#"rs_project_Input"] count];
NSLog(#"Save Btn: No of rows for saving %d",noOfRow);
for (row1=0; row1<noOfRow; row1++)
{
NSLog(#"Row is %d",row1);
path = [NSIndexPath indexPathForRow:row1 inSection:0];
Input_Details *inputDetailsObject1=[[self sortInputs] objectAtIndex:path.row];
/*
Update the input details from the values in the text fields.
*/
EditingTableViewCell *cell;
cell = (EditingTableViewCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row1 inSection:0]];
inputDetailsObject1.mh_Up= cell.cell_MH_up.text;
inputDetailsObject1.mh_down=cell.textField.text;
NSLog(#"Saving the MH_up value %# is saved in save at index path %d",inputDetailsObject1.mh_Up,row1);
[masterController saveContext];
}
[self.tableView reloadData];
}
My problem is that the code is not helping in saving the data. Plz help.
Thanks
You try to use the table view cells as a data source, which will not work (apart from being a bad design). The problem is that
[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row1 inSection:0]]
returns nil if the cell at that row is currently not visible. (A table view allocates only cells for the visible rows and reuses these cells as you scroll up or down.)
You have to track changes to the text fields immediately, e.g. by implementing a textFieldDidEndEditing: delegate function, and store the changed text in your data source.

Find selected cells in a TableView

I'm writing an iPhone application with a tableview which displays a list of items,each one with a checkmark. I can selected/deselect each item just with one click. When I press a button [DONE] I would like to iterate along all the cells and check which one has the checkmark enabled. Something like:
for (int i = 0; i < [fullDataset count]; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
NSLog(#"THIS CELL IS SELECTED!");
}
}
Now,the problem is that using this procedure I get only the cell which are selected and which are CURRENTLY DISPLAYED. I want to be sure that the procedure runs across ALL the cell,even the ones not displayed. I might use another data structure for keeping track of the selection but it looks to be a bit redundant.
Any idea?
Thanks a lot!
Claus
You can't count on the cells to tell u if selected or not, cells get reused and always change there state.
You need to manage a separate NSSet of the selected indexPaths, when user tap on a cell, u add this indexPath to the set, when he deselect the cell u delete the indexPath from the set.

TableView Cell reuse and unwanted checkmarks - this is killing me

Apple's iOS TableView and cell reuse is killing me. I searched and searched and studied, but can't find good docs or good answers. The problem is that when the TableView reuses cells things like Checkmarks (cell accessory) set on a selected Cell are repeated in the cells further down in the table view. I understand that cell reuse is by design, due to memory constraints, but if you have a list with say 50 items, and it starts setting extra checkmarks where they're not wanted, this makes whole endeavor useless.
All I want to do is set a checkmark on a cell I've selected. I've tried this using my own custom cell class, and standard cells generated by a boiler plate TableView class, but it always ends up the same.
Apple even have an example project called TouchCell you can download from the dev center, that is supposed to show a different way of setting a checkmark using a custom cell with an image control on the left. The project uses a dictionary object for a data source instead of a muteable array, so for each item there is a string value and bool checked value. This bool checked value is supposed to set the checkmark so it can track selected items. This sample project also displays this goofy behavior as soon as you populate the TableView with 15+ cells. The reuse of cells starts setting unwanted check marks.
I've even tried experimenting with using a truely unique Cell Identifier for each cell. So instead of each cell having something like #"Acell" I used a static int, cast to a string so the cells got #"cell1", #"cell2" etc. During testing though, I could see that hundreds of new cells where generated during scrolling, even if the table only had 30 items.
It did fix the checkmark repeat problem, but I suspect the memory usage was going way too high.
It's as though the cells that are not currently in the viewable area of the table are created all over again when they are scrolled back into view.
Has anyone come up with an elegant solution to this irritating behavior?
cell reusing can be tricky but you have to keep 2 things in mind:
Use one identifier for one type of cell - Using multiple identifiers is really only needed when you use different UITableViewCell-subclasses in one table view and you have to rely on their different behaviour for different cells
The cell you reuse can be in any state, which means you have to configure every aspect of the cell again - especially checkmars / images / text / accessoryViews / accessoryTypes and more
What you need to do is to create a storage for your checkmark states - a simple array containing bools (or NSArray containing boolean NSNumber objects respectively) should do it. Then when you have to create/reuse a cell use following logic:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *reuseIdentifier = #"MyCellType";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if(cell == nil) {
/* create cell here */
}
// Configure cell now
cell.textLabel.text = #"Cell text"; // load from datasource
if([[stateArray objectAtIndex:indexPath.row] boolValue]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
then you will have to react on taps:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[stateArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:![[stateArray objectAtIndex:indexPath.row] boolValue]]];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
Just remember to use NSMutableArray for your data store ;)

Resources