Issue with UITableViewCell and checking clicks - iphone

So I am using a uitableview to display multiple images and labels. I want to be able to check the text of the label of the cell that is clicked so that I can identify which one is clicked.
The reason I do this is because I want to do a different action for one cell being clicked, and a different action for another.
This is how I populate my cells (from a prototype cell) With the cell defenition from a class called CustomCell
//tableview datasource delegate methods
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return cellIconNames.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
cellIconName = [cellIconNames objectAtIndex:indexPath.row];
NSString *cellIconImageName = [[self cellIconImages] objectAtIndex:[indexPath row]];
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if(cell == nil){
cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.rightLabel.text = [cellIconNames objectAtIndex:indexPath.row];
cell.carrierImage.image = [UIImage imageNamed:cellIconImageName];
cell.urlString = [cellIconNames objectAtIndex:indexPath.row];
return cell;
}
The way I am checking to see which one is clicked is by doing this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;{
CustomCell *cell = (CustomCell*)[tableView cellForRowAtIndexPath:indexPath];
//[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"www.google.com"]];
if ([cell.urlString isEqualToString:#"Aetna"]) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"www.aetna.com"]];
}else if([cell.urlString isEqualToString:nil]){
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"www.google.com"]];
}
NSLog(#"cell was clicked %#", cell);
}
When i click a cell, nothing happens. Now i have made that NSLOG so that i can make sure the cells are being read correctly which they are.
I also have commented out my testing line of code, I had the if else statment commented out and just ran the one commented line of code, and nothing happens.
Please help me, i have no idea what is going wrong :/

Try putting the URL method into the string (e.g. http://).

Just double-checking that you've both added your UITableViewController as a UITableViewDelegate and have either programatically or in Interface Builder have wired the delegate back to your controller?

In your didSelectRowAtIndexPath method you shouldn't be looking at the cell at all. You should look at the data in your data model. Just like you did in cellForRowAtIndexPath, get the data for the indexPath. Then do the appropriate check against the data.

I Dont know why u are not understanding it easily just use indexpath.row in didSelectRowAtIndexPath and u will simply get the desired cell.

Related

Linking UITableView with a NSMutableArray

I've been trying to fill a UITableView with data from a NSMutableArray. I have a View-Based application project and so far I've tried every tutorial I found but so far, it just doesn't work. I linked the dataSource and delegate to the File's Owner, I added the procotols UITableViewDelegate and UITableViewDataSource to my UIViewController, I create an array containing 3 strings just to try and debug, everytime I load the app, the table stays empty.
I'm not sure what could be my error, or where I should look to find the problem, if you guys got any idea that would be nice.
Thank you
-(NSInteger) tableView:(UITableView *)table numberOfRowsInSection: (NSInteger)section
{
return [yourArray count];
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [yourArray objectAtIndex:row];
return cell;
}
That should populate the table from an array. I've used it several times in my app.
I guess you did forget to call -reloadData on the table view.
Make sure the dataSource and delegate are properly connected to the view controller, also make sure your UITableView is property connected with the outlet if you are using storyboards or a xib file.
If nothing works I recommend you to use XLData that makes UITableView data loading much more simple to implement.

how to set accessoryType when cell has been selected

I have been trying to figure out how to set the accessoryType to UITableViewCellAccessoryCheckmark when the cell is selected but am having trouble finding a decent example of this.
If you know how to do this or a good tutorial could you please let me know that would be great.
To restrict the user to just one selection, meaning to create an exclusive list of one choice only, you could follow these steps;
Firstly, have a global index path declared in your .h file to keep track of the already selected cell ->
NSIndexPath *oldIndexPath;
When you create the cells, be sure to set the accessory type to none, so that no cell is selected by default when the table is seen;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CallIdentifier"];
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Finally, in the didSelectRowAtIndexPath delegate method, add the following code which will remove the checkmark from the already selected cell, and add a checkmark to the newly selected one.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (oldIndexPath==nil) { // No selection made yet
oldIndexPath=indexPath;
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
else {
UITableViewCell *formerSelectedcell = [tableView cellForRowAtIndexPath:oldIndexPath]; // finding the already selected cell
[formerSelectedcell setAccessoryType:UITableViewCellAccessoryNone];
[cell setAccessoryType:UITableViewCellAccessoryCheckmark]; // 'select' the new cell
oldIndexPath=indexPath;
}
}
Hope this works out! :)
Something like this may work:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self tableView:myTableView cellForRowAtIndexPath:indexPath];
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
To answer the comment below, just push a viewController in the same method like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self tableView:myTableView cellForRowAtIndexPath:indexPath];
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
// Then push a new view
iPhoneCustomViewController *myVC = [[iPhoneCustomViewController alloc] initWithNibName:#"iPhoneCustomViewController" bundle:nil];
[self.navigationController pushViewController:myVC animated:YES];
[myVC release];
// And deselect the row (if desired)
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Did you know that:
1.) UITableView keeps track of the index paths for the rows that have been selected? It's in an array called indexPathsForSelectedRows
2.) UITableView has a flag you can set to make it either single or multiple selection. You can change it by calling the setter setAllowsMultipleSelection:(BOOL).
So, assuming that the table has been set to single selection, we can do the following in the tableView:CellForRowAtIndexPath method ...
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *simpleTableIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[[cell textLabel] setText:#"Some Text"];
NSArray *selectedIndexPaths = [tableView indexPathsForSelectedRows];
if ([selectedIndexPaths containsObject:indexPath]) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}else{
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
return cell;}
This implementation of CellForRowAtIndexPath will give you a clean checkmark with no gray background when a cell is selected. You will need to set the checkmark in the didSelectRowAtIndexPath delegate method to make sure a cell gets the checkmark the moment it gets selected.
No need to create separate ivars or anything else to keep track of what was or wasn't selected. It's all neatly contained in the UITableView as Apple intended.
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
newCell.accessoryType=UITableViewCellAccessoryCheckmark;
Implement this in didSelectRowAtIndexPath delegate method
From the docs:
The delegate handles selections in this method. One of the things it
can do is exclusively assign the check-mark image
(UITableViewCellAccessoryCheckmark) to one row in a section
(radio-list style). This method isn’t called when the editing property
of the table is set to YES (that is, the table view is in editing
mode). See "Managing Selections" in Table View Programming Guide for
iOS for further information (and code examples) related to this
method.
Here is an example:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]
cell.UITableViewAccessoryType = UITableViewCellAccessoryCheckmark;
}

reloaddata doesnt seem to be working

I may be using it incorrectly but i think i have it right. I load data into my UITableViewController like so.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CoCoachAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
switch (indexPath.section) {
case 0:
[cell.textLabel setText:#"Click to add new rower"];
cell.textLabel.textAlignment = UITextAlignmentCenter;
break;
case 1:
[cell.textLabel setText:[[appDelegate teamRoster]objectAtIndex:indexPath.row]];
break;
}
return cell;
}
And everything works fine, i then push the user to a different viewController and allow them to enter their name into a text field. I take their name and add it into the same array that populated my UITableViewController, and from the UITableViewController i call:
[self.tableView reloadData];
But nothing happens. If i check my array i can see that it has the correct number of objects, and their name is the last entry, but the tableview remains unchanged...
I was thinking maybe i just dont know how to use reloadData, but from what i have been reading elsewhere this should be working.
Any thoughts?
Your crash is due to the fact that you are doing
NSLog(#"%#",[[appDelegate teamRoster] count]);
when you should be doing
NSLog(#"%d",[[appDelegate teamRoster] count]);
Using %# sends the objec the message description, which does not work for ints (or floats or BOOLs).
The NSLog crashes because you are using the wrong formatter type (#"%#"), it should be:
NSLog(#"%d",[[appDelegate teamRoster] count]);
Other than that, where is reloadData being called from? Make sure it's happening on the Main thread.

why [self.tableView reloadData] does not Work?

This is the code for cellForRowAtIndexPath: method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
if (cell == nil) { cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SimpleTableIdentifier] autorelease];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [array objectAtIndex:row];
return cell;
}
When i use [self.tableView reloadData]; nothing happening?
You need to implement at least the tableView:numberOfRowsInSection: method as part of the UITableViewDataSource protocol, and tableView:cellForRowAtIndexPath: (which you already did). You should also implement numberOfSectionsInTableView:.
Then you need to make sure that your class is actually used as a data source:
self.tableView.dataSource = self;
That needs to be either done via Interface Builder or in awakeFromNib or some other method like viewDidLoad:.
Do you check your dataSource and delegate of UITableView ? I think the dataSource is nil or something else.
Try putting a break point in cell for row and see if it is called when u call reloadData. Also pls check if the changes are already made to array from which the cells are populated and make sure the table view is connected to its datasource and delegate.

How do you change the textLabel when UITableViewCell is selected?

I want to change the textLabel and detailTextLabel of a cell when it has been selected.
I've tried the following, but no change occurs:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MyAppDelegate *appDelegate = (MyPhoneAppDelegate*)[[UIApplication sharedApplication] delegate];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.detailTextLabel.text = #"xxxxx";
cell.textLabel.text = #"zzzzz";
[tableView reloadData];
}
I agree, reloading the table view will actually dump and reload/display all the cells using tableView:cellForRowAtIndexPath: and use the original data, not the updated #"xxxxx" and #"yyyyy" in your tableView:didSelectRowAtIndexPath: method.
In a little test project I was able to change the labels upon selection with:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath];
cell.textLabel.text = #"it was tapped";
}
You should not be trying to reload the table while a cell is selected. Instead, try
[cell setNeedsLayout]
after you make the above changes to the labels.
Also, is there a reason you're making a reference to the app delegate in the method?
Try to reload the cell you selected (described by indexPath) :
[yourTableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
Create a New iPad Project (Split View) and Now go through the Classes->Files. The easiest way's been given there. The XCode's Generated Codes.
Sample Code Lines :-
cell.textLabel.text = [NSString stringWithFormat:#"Row %d", indexPath.row];
You can use them in cellForRowAtIndexPath ||&& didSelectRowAtIndexPath ..
Not sure what you're trying to do with the delegate but you should try calling the tableView already instantiated; i.e. call
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath: indexPath];
Maybe I'm not clear
What I'm saying is that you are instantiating a new empty table view
UITableViewCell *cell = [**tableView** cellForRowAtIndexPath: indexPath]; //cell has nothing it is new.
consider replacing to call the old
UITableViewCell *cell = [**self.tableView** cellForRowAtIndexPath: indexPath]; //now you have one that has a textField already in it
Did you try to refresh only the selected cell instead of reloading the whole table ?
[cell setNeedsDisplay];
instead of
[tableView reloadData];
This will have better performance and I'm not but I suppose that selection is lost if you refresh the whole table (this may be the reason why you don't see any change in the end)....