UITableView not selecting properly - objective-c

I am working on an iPhone app, where I have a UITableView which is being populated with an XML feed through a URL.
Say for instance three of the cells are populated.
If I tap on the first cell nothing happens, however if I tap on the second or third cell, it takes me to the second screen related to cell one, and the same happens with the other cells - tap on it nothing, tap on another and it takes me to the second screen of the previous one selected.
I have never had this happen before and am rather confused.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:#"UITableViewCell"];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
LocationsItem *atm = [[locations atms] objectAtIndex:[indexPath row]];
[[cell textLabel] setText:[atm atmName]];
float distance = [[atm atmDistance] floatValue];
NSString *distanceString = [NSString stringWithFormat:#"%0.2f miles from current location", distance];
[[cell detailTextLabel] setText:distanceString];
return cell;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
LocationsItem *atm = [[locations atms] objectAtIndex:[indexPath row]];
ATMDetailsController *detailsController = [[ATMDetailsController alloc] init];
[detailsController setCurrentATM: atm];
[[self navigationController] pushViewController:detailsController animated:YES];
}
Thanks,
Nick

You answered your own question. The issue is that you used tableView:deselectRowAtIndexPath: instead of tableView:didSelectRowAtIndexPath:
What is noteworthy is that this is from the unfortunate fact that deselect comes before did in the dictionary, and therefore, xcode's normally awesome code completion hinks you!
Now to go get those hours of debugging back!

Related

How to directly edit a row in a UITableView, without entering in Editing Mode

In a UITableView, I would like to be able to edit the cell.textLabel.text property of the row, when such row is touched.
In other terms, I would like to be able to edit the row directly touching it, instead of entering into edit mode.
How can I implement this?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CMTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CMTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
int tagsCount = [[currentComic Tags] count];
[[cell textField] setTag:[indexPath row]];
[[cell textField] setText:[tagsDisplayName objectAtIndex:[indexPath row]]];
return cell;
}
And this is the subclass CMTableViewCell:
...
-(void)viewDidLoad
{
textField = [[UITextField alloc] init];
[textField setFrame:CGRectMake(5,5,50,400)];
[self addSubview:textField];
}
Add UITextField without borders as subview. Before adding it to subview - set Tag nubmer to UITextField from indexPath.row at tableview cellForRowAtIndexPath method. When user entered data - save it with UITextFieldDelegate methods when "Return" button was pressed. Unfortunately I can't give you code, because right now I'm on Windows. Home this will help
UPDATE: Tag number needed to change data in your DataSource. When you pressed "Return" button in your UITextField, you can save changed by getting UITableViewCell by this tag number from UITextField.
It's simple:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.textLabel.text = #"...";
}
UPDATE
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITextField *textField = [[UITextField alloc] init];
[textField setTag:[indexPath row]];
[tagsTableView addSubview:textField];
FreeAndNil(textField);
}

uiwebview in every tableviewcells

I need to display each webview in each of the tableviewcell in my Uitableview.When using the below code,when there are 2 elements,the first cell is empty but second cell is correct.hrs and hrsHtml contains all values,the problem is only the last data is displaying in their appropriate cell in tableview.Other cells are just blank.Also is total cells is 2,first we can only been able to see the 2nd cell only,but after scrolling tableview reloads and 2nd cell disappears and 1st cell gets displayed.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [brId count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil) {
cell = [[ UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell.contentView addSubview:hrs];
hrsHtml = [NSString stringWithFormat:#" <font size=\"2\" face=\"Arial\">%# </font>",[html objectAtIndex:indexPath.row]];
[hrs loadHTMLString:hrsHtml baseURL:nil];
return cell;
}
Screenshot when tableview appears,Only webview in cell 2
Screenshot when tableview scrolls,Only webview in cell 1,cell 2 disappears
Since hrs and hrsHtml are single objects, you only have one of each even though you have multiple cells. If you modify hrs, it will change for all cells since they seem to be sharing it. (Unless you have other code somewhere that changes the objects that those variables point to.)
Another odd thing is that you use a brId array to determine the number of rows and a html array to get the row content. If those ever get out of synchronization, you will have problems.
Also, you should only add a subview to a cell when you create a new one.
- (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:nil] ;
}
hrs = [[UIWebView alloc] initWithFrame:CGRectMake(10,0,320,84)];
hrs.userInteractionEnabled = YES;
hrs.backgroundColor = [UIColor clearColor];
hrsHtml = [NSString stringWithFormat:#" <font size=\"2\" face=\"Arial\">%# </font>",[html objectAtIndex:indexPath.row]];
[hrs loadHTMLString:hrsHtml baseURL:nil];
[cell.contentView addSubview:hrs];
hrsHtml = nil;
return cell;
}
Now the webview loads correctly in every tableviewcell.
i think you have problem in initializing cell try below code
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
}

TableView: didSelectRowAtIndexPath, How to catch a row name

I fill my tableView with random data. So i don't know how many row i have and how to redirect it to screen i want to. I filled:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyClass *currentScreenElement = [self.tableRows objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:currentScreenElement.objectName];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:currentScreenElement.objectName];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.textLabel.text = currentScreenElement.objectName;
return cell;
}
And this works fine. I have a tableView with filled rows. Now i want to redirect to new screen and I doing it with:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NewScreenClass *myScreen = [[NewScreenClass alloc] init];
self.detailViewController = [[CreateView alloc] initWithScreenDef:[myScreen returnScreenFromName:#"second"]];
[self.navigationController pushViewController:self.detailViewController animated:YES];
}
Of course i know that what I actualy do here is create the same screen for every row. But how can i redirect to screen i want to?
My currentScreenElement object contains properties: objectName (display name in tableView) and objectTarget (screen definition). Both NSString.
And my question is should i save a my currentScreenElement to row patch somehow or maybe I should catch a objectName from dislay name?
In didSelectRowAtIndexPath you can get the cell by using
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
Then just get the text from the cell.
cell.textLabel.text
Why can't you use the self.tableRows array again?
MyClass *currentScreenElement = [self.tableRows objectAtIndex:indexPath.row];
NSString *title = [currentScreenElement objectName];
It's the same thing you did to setup that row, just use it again.

UISearchBarDelegate and UITableView not working together?

I have a table view controller with a standard UISearchBar
I want to replace the first row in the table with the text in the search bar as it gets typed.
I thought this would work but it doesn't:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
// results is a mutable array with an empty string at index 0
[[self results] replaceObjectAtIndex:0 withObject:searchText];
[[self tableView] reloadData];
}
If I log the results array to the console it is correctly replacing the object,
but it is not getting picked up by the table view.
I have the table data source set up as per usual:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[self results] count];
}
- (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];
}
// Configure the cell...
[[cell textLabel] setText:[[self results] objectAtIndex:[indexPath row]]];
return cell;
}
If I just use insertObjectAtIndex: or insertObject: it does show up the results. Just not when I'm trying to replace first object.
Help please! :)
Ok figured it out.
Really stupid too....
The searchBar was covering the first row of the tableView, so I couldn't see it updating.
Doh.
Try killing this line: if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } . The reason I say this is that you are alloc-ing each cell.
Here's a post that I had stashed away: iPhone: How to purge a cached UITableViewCell

UITableView showing (null) for first row

I am updating a UITableView with CoreData. On startup, the first row is showing as (null). If I scroll down/up, it loads though. It just doesnt show initially.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
[cell setAccessoryType: UITableViewCellAccessoryDisclosureIndicator];
}
// set text for each cell
[cell.textLabel setText: [dataManager getProjectValueForKey: #"Title" atIndex: [indexPath row]]];
[cell.detailTextLabel setText: [[[dataManager getProjectValueForKey: #"pid" atIndex:[indexPath row]] stringByAppendingString: #": "] stringByAppendingString: [dataManager getProjectValueForKey: #"Sponsor" atIndex:[indexPath row]]]];
return cell;
}
dataManager is what is talking to Core Data. I feel like it might be lagging behind or something on startup so the cell is trying to show the data before it is ready. But I don't know.
Actually, there is a great "dataManager" already built into Core Data. It is called NSFetchedResultsController. You can always retrieve the correct data object for your table cell with
[[self.fetchedResultsController fetchedObjects] objectAtIndex:indexPath.row];
This is typically done inside tableView:cellForRowAtIndexPath:, and not in some other helper function. The fetched results controller will take care of everything that is necessary to retrieve the data that is needed in order to display it.
See also the numerous Core Data code examples from Apple for this common design pattern.