UITableView didSelectRowAtIndexPath only fired sometimes - iphone

I know this is going to be one of those head-smacker moments.
I have a UITableView from which I need to delete cells. Problem is, didSelectRowAtIndexPath is only called if I first tap the row and then swipe to show the delete button. If I swipe the row without explicitly tapping the row, then I get an EXC_BAD_ACCESS error. I put an NSLog into didSelectRowAtIndexPath and can see the indexPath array when I tap the cell, but nothing if I just swipe without clicking.
I've done my share of searching and I'm 99% sure my delegate is hooked up correctly (usually problem #1) and didn't type didDeselectRowAtIndexPath (usually problem #2). I also have in my .h file (problem #3).
Thanks in advance.
EDIT:
I should have said: If I swipe the row without explicitly tapping the row, then I get an EXC_BAD_ACCESS error when I tap the Delete button. If I tap the cell and then swipe, I can tap Delete and it deletes as expected.
EDIT:
(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];
}
NSSortDescriptor *aSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
[bandList sortUsingDescriptors:[NSArray arrayWithObject:aSortDescriptor]];
NSDictionary *dict = [bandList objectAtIndex:indexPath.row];
cell.textLabel.text = [dict objectForKey:#"name"];
return cell;
}
- (void)tableView: (UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
NSLog(#"IndexPath: %#", [indexPath description]);
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
NSDictionary *selectedBand = [bandList objectAtIndex:indexPath.row];
NSString *selectedBandId = [selectedBand objectForKey:#"id"];
[self deleteMyBand:selectedBandId];
bandList = [self getSavedBands];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}

These lines jump out at me:
NSDictionary *selectedBand = [bandList objectAtIndex:indexPath.row];
NSString *selectedBandId = [selectedBand objectForKey:#"id"];
I don't understand your reasoning for taking a value from an array, sticking it into a dictionary, then getting a string out of that dictionary. Shouldn't the value returned from
[bandList objectAtIndex:indexPath.row];
Be the same as what you get in selectedBandId?
Also, I can't analyze it any further when I don't know what "deleteMyBand" and "getSavedBands" do. Try commenting out those calls and seeing if the visible row itself can be deleted. That may tell you where the problem is.

Not exactly sure why, but the fact that I was using a sorted NSMutableArray for my source data seems to have been the problem. When I was deleting the row from the table and updating the MutableArray, I got the crash. However, if I created my source data as an NSArray, made a mutableCopy of the array into a temporary MutableArray, removed the row, resorted the array, and then wrote the MutableArray back out to an NSArray, everything is peachy.
I don't think this explanation makes sense, but it's the pattern I'm seeing. If anybody can think of why this might be working, please enlighten me. My gut tels me it was the sort, but my gut hasn't been correct much lately.

Related

How to use UITextField to input information to UITableView?

I am trying to make a ToDo list app and I can't for the life of me seem to figure out how to make the text box's typed text go into a box with a tick box for me to be able to change to completed.
Can anyone help me? I am just getting started in Xcode so please explain why/how it works that way I can learn for the future. Thanks guys!
App Rendering (What I am trying to make)
http://imgur.com/wcNXu0z
Currently in Xcode (What I have so far)
http://imgur.com/PLUVaVg
You need to create an IBAction for add button. So its get called when you click the button and store the entered text in UItextfield in an array and you will use that array to add rows in your table.
For example consider the code :
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [dataArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
[cell.textLabel setText: [dataArray objectAtIndex:indexPath.row];
return cell;
}
-(IBAction)addCity:(id)sender
{
[tableView beginUpdates];
[dataArray addObject:#"City"];
NSArray *paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:[dataArray count]-1 inSection:1]];
[[self tableView] insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationTop];
[tableView endUpdates];
}
I'd strongly recommend you check out the free Sensible TableView framework. The framework should help you automatically create your text fields and automatically fill/save their data.

Issue with UITableViewCell and checking clicks

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.

UITableView scrolling crashes app

When i scroll UITableView it crashes the app. Here is code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *tempDict = [albums objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"ImageCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
} else {
AsyncImageView *oldImage = (AsyncImageView *)[cell.contentView viewWithTag:999];
[oldImage removeFromSuperview];
}
I set the breakpoints and it stops at line
NSDictionary *tempDict = [albums objectAtIndex:indexPath.row];
What am i doing wrong?
Thanks in advance.
I am not sure, first of all please check the total number of rows and your array count. They must be same. If still it crashes then put this line
NSDictionary *tempDict = [[albums objectAtIndex:indexPath.row] copy];
Check size of albums array. May be it is smaller then indexPath.row or it was released somewhere.
Make sure you are not reading out of bounds of your NSdictionary.
Check your return value in the tableView:numberOfRowsInSection: dataSource method.
The most likely reason for a crash on that line is that your table view has more rows than you have items in your albums array. Normally, in a setup like this, you'd have exactly the same number of rows in your table, and your implementation of –tableView:numberOfRowsInSection: would look like this
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// assuming that there is only one section
return [albums count];
}
I solved this problem. Actually in the $cellForRow ,I was trying to get information from server, I did not apply lazy loading there. Because of that while scrolling the tableView, app was crashing.
Thank you to all for your help.

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.

How can a checkmark state be saved in core data?

I have a list app where users hit the + button and enter in an item that they want to appear in the list and hit save. The table is saved with core data. The only problem is when the cell is taped I want a checkmark to be displayed. Ive enabled multiple selection with
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
if (thisCell.accessoryType == UITableViewCellAccessoryNone) {
thisCell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
thisCell.accessoryType = UITableViewCellAccessoryNone;
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
I would like the checkmarks to be persisted in the cell after the user exits. I have created an attribute in my entity called "checks" and gave it the type of boolean but I dont know how to make it where if you hit a row then a check appears and is persisted. Any help would be greatly appreciated. Thanks
This is how I do it. One notable point: CoreData does not store booleans, so any property labeled "boolean" is actually of type NSNumber. You've got to remember to convert back and forth when dealing with CoreData and boolean values.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *selectedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
if ([[selectedObject valueForKey:#"isDone"] boolValue]) {
[selectedObject setValue:[NSNumber numberWithBool:NO] forKey:#"isDone"];
} else {
[selectedObject setValue:[NSNumber numberWithBool:YES] forKey:#"isDone"];
}
}
I have my UITableViewController set as the the delegate for the NSFetchedResultsController, so the changes I made to the managed objects in the query ^^^ will cause the following two methods to be run.
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *defaultCellIdentifier = #"Item";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:defaultCellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:defaultCellIdentifier] autorelease];
}
NSManagedObject *item = [[self fetchedResultsController] objectAtIndexPath:indexPath];
cell.textLabel.text = [item valueForKey:#"name"];
if ([[item valueForKey:#"checks"] boolValue]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Here's how everything ties together
User clicks on a row
tableView:didSelectRow... method changes the "isDone" property of the appropriate managed object.
the fetched results controller notices that a managed object has changed and calls the controllerDidChangeContent method on its delegate.
My controllerDidChangeContent method just reloads all the data in the table view
When the tableView is reloaded, my tableView:cellForRow... method checks the "isDone" property of the managed item to see if the cell should have a checkmark or not.
And just so you don't get confused, I initially used a generic NSMangagedObject to store row state, which is why the first method I posted says, [selectedObject valueForKey:#"isDone"]. Later I switched to a subclassed managed object named JKItem, which is why the second set of methods is able to use item.isDone without generating a compiler warning.