I have this bizarre problem. I'm making a checklist program with XCode and I'm using UITableView with UITableViewCellAccessoryCheckmark. I can select cells and the checkmark will appear, but somehow, other cells that I have NOT yet selected below will also have a checkmark appear. Any ideas?
Here's my check mark coding:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
cell = [aTableView cellForRowAtIndexPath: indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
I don't know if this affects it, but I also implemented this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}
// Configure the cell.
if(tableView == Table1){
switch(indexPath.section){
case 0:
cell.textLabel.text = [array1 objectAtIndex:indexPath.row];
break;
case 1:
cell.textLabel.text = [array2 objectAtIndex:indexPath.row];
break;
case 2:
cell.textLabel.text = [array3 objectAtIndex:indexPath.row];
break;
}
//cell.textLabel.text = [NSString stringWithFormat:#"Row %d", indexPath.row];
}
if(tableView == Table2){
cell.textLabel.text = [array4 objectAtIndex:indexPath.row];
}
return cell;
}
Thanks.
Set the cell.accessoryType each time you call tableView:cellForRowAtIndexPath:. Otherwise, when you reuse a cell, you'll get it's accessoryView instead of what you're expecting.
So, yeah, you'll need to keep track in when NSIndexPaths are selected by some method other than just looking at the accessoryType.
You should keep the checked/unchecked info in data source (array).
I also advise you to remove the cell.accessoryType = UITableViewCellAccessoryNone; line.
This line will be executed only for few first cells. All the other cells will be "reused" - meaning that the old (already initiated) cells will be used, and you will have to modify the details that are displayed on these cells (all inside cellForRowAtIndexPath as you do now).
In addition you will have to add a similar line (something like cell.accessoryType = ([[array objectAtIndex:indexPath.row] boolValue] ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;).
In general, I suggest you to use one array for holding the data for your table, when each item in the array will be a dictionary. This way you will be able to hold the texts and the boolean checkmarks (inside NSNumber) and easily access them when needed.
Related
I am new in iPhone application development. I am currently working on XML parsing. I am extracting records from an xml file and storing it in an mutable array. I have a table view and i am loading the table view from that mutable array. I get 18 rows in the table view which i found by debugging. The problem is when i scroll down upto 10 rows it moves well but as 10th row appears the app crashes. i get the error of EXC_BAD_ACCESS. Here is my code where the cell gets loaded. Thanks.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
Location *record = [[Location alloc] init];
record = [[parse locationarr] objectAtIndex:indexPath.row];
cell.textLabel.text = record.locationname;
return cell;
}
}
There are some misstakes in the code you post, first you only return a cell is the table isn't return a cell for dequeueing
Thus changing you code likewise will solve that problem:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
Location *record = [[Location alloc] init];
record = [[parse locationarr] objectAtIndex:indexPath.row];
cell.textLabel.text = record.locationname;
return cell;
}
Also having to alloc and init a Location every time is very costly, it's better to have a Location with in the class that you call every time a cell is needed.
Beter yet is to just grab the data for the cell only and not do any lengthy method in the tableVieew:cellForRowAtIndexPath: method.
your mistake is " return cell" which is written in inside the if condition take it outside also row title label text set out side condition.like this way..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
Location *record = [[Location alloc] init];
}
else
{
// get record object here by tag.
}
record = [[parse locationarr] objectAtIndex:indexPath.row];
cell.textLabel.text = record.locationname;
return cell;
}
You need to write this snippet
`record = [[parse locationarr] objectAtIndex:indexPath.row];
cell.textLabel.text = record.locationname;`
out of if block.
Enjoy Programming!!
Please check the below code..
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// I may use this object to maintain check state.
ab_user_info *obj = nil;
obj = [self.listData objectAtIndex: [indexPath row]];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[contact_table reloadData];
}
As per the above code, I have checked all the table I am clicking, What should I do to uncheck again, I know I should change accessory type to None, but when, how do I know previously it was checked? Is there any API which tell us the accessary type of cell.
I have done in other table view by adding an extra member in my modal obj to track the checked and unchecked cell, however I just want to know is there any way without that?
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
tableView is a Data Presenter view object
TableView is just used to 'display' data, it is not the manager or tracker of data. You need to track the attributes of data in the backend. I mean if you want to keep track of which all rows are checked or unchecked, it cannot be managed by TableView, you need to take care of it either by using NSArray or any other object type.
Try below code :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// I may use this object to maintain check state.
ab_user_info *obj = nil;
obj = [self.listData objectAtIndex: [indexPath row]];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
}else{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
I have seen other questions on here related to this, but I have their solutions in place, and things still move around when I scroll.
Basically, I have a table of data and I want the first and only the first row to have a UITableViewCellAccessoryDisclosureIndicator. The problem is, when I scroll around, the indicator duplicates, deletes, and moves to other cells. Here is my code..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if(indexPath.row == 0) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.textLabel.text = [tabledata objectAtIndex:indexPath.row];
return cell;
}
The problem is something with the indexPath.row variable.. its somehow returning 0 in other cells that aren't the very first (when it comes to displaying cells). HOWEVER... the data is always right from my array(which implies the value HAS to be correct) and in my
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
method, i only wish to change screens when row 0 is clicked.. and regardless of where I have scrolled to, no cells trigger except the very first. So it seems THAT check is always correct while the one inside cellForRowAtIndexPath is not...
Most likely, you are re-using cells that already have the accessoryType set. You need to explicitly set it to NOT show on cells where it shouldn't.
if(indexPath.row == 0){
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
I have a tableview, i need to have a checkmark displayed everytime i select a row. (Multiple selection) My code is given below. I am also able to unselect a row.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *RootViewControllerCell = #"RootViewControllerCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RootViewControllerCell];
if(nil == cell)
{
cell = [[[UITableViewCell alloc]initWithFrame:CGRectZero reuseIdentifier:RootViewControllerCell] autorelease];
}
cell.textLabel.font = [UIFont fontWithName:[NSString stringWithFormat:#"HelveticaNeue-Bold"] size:12];
textView.textColor = [UIColor colorWithRed:0.281 green:0.731 blue:0.8789 alpha:1];
cell.textLabel.text = [optionsArray objectAtIndex:[indexPath row]];
if (pathIndex == indexPath)
{
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
pathIndex = indexPath;
[surveytableView reloadData];
}
But i have a problem with the cells being reused. When i select a cell another cell elsewhere also gets selected. Only the checkmark (or no checkmark) is getting reused other details like the row title, etc., don't get reused. Any solutions to fix this. Thanks in advance.
Add it to cellForRowAtIndexPath:
if ([tableView.indexPathsForSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else if (![tableView.indexPathsForSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryNone;
}
Worked for me
At your
if (pathIndex == indexPath)
you're comparing pointers not the values of them, try
[pathIndex isEqual:indexPath]
or use
- (NSComparisonResult)compare:(NSIndexPath *)otherObject;
Next you're assigning a value to pathIndex without retaining or copying it like
pathIndex = [indexPath copy];
(of course now since you're retaining the value, before copying your new object you have to release the previous one [pathIndex release];)
Finally, no multiple selection is provided by your implementation, only single selection. You could try adding and removing NSIndexPath objects to an NSMutableArray and check against their presence in your mutable array at cellForRowAtIndexPath instead.
The issue is that you only do something with the accessory if the current row matches pathIndex.... so what if it is a normal cell...? You never set it back. You want...
cell.accessoryType = UITableViewCellAccessoryNone;
if ([pathIndex isEqual:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
It is good practice to reset the cells before you set any specific properties.
I just have a basic (noob) question about cellForRowAtIndexPath get called?
I'm working through example code and I don't see it explicitly called anywhere?
Does any component of type UITableViewComponent automatically call this function when it is created?
Thanks
When a UITableView is displaying this method gets called per row. In it you will customize each cell with particular data for display.
Here's the class reference.
Here's a sample:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"FriendCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
NSUInteger row = [indexPath row];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
Item *i = [itemArray objectAtIndex:row];
cell.textLabel.text = [i name];
cell.detailTextLabel.text = [i brewery];
[i release];
return cell;
}
This is called for each cell when the corresponding UITableView gets drawn. An index path is passed in, and based on the section and cell numbers, your code should generate a UITableViewCell to be displayed in the UI.
You can look here for a quick tutorial into how UITableViews work.