I have a UITableView whose cellForRowAtIndexPath is printed below. When I call reloadData on the tableView, the application crashes, and there is no clear EXC_BAD_ACCESS or anything - it simply returns to main. The problem has arisen since I added the label subview, which leads me to think there may be some problem with releasing the subview/reusing the cell.
Can anyone see what's causing the problem?
Thanks in advance,
Ed
Here's the code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//---
for(UIView *eachView in [cell subviews])
[eachView removeFromSuperview];
//Initialize cell label
UILabel *myLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 290, 25)];
[myLabel setFont:[UIFont fontWithName:#"HelveticaNeue" size:14.0]];
[myLabel setTextColor:[UIColor darkGrayColor]];
myLabel.text =#"Label";
[cell addSubview:myLabel];
[myLabel release];
return cell;
}
Related
I'm creating a table view and custom view for my UITableView. Basically I have FirstViewController with table view and CustomTableViewCell. In custom cell, I had link all the controls to header and implements in the file which superclass with UITableViewCell. I'm creating a button, and want to programatically using "instantiateViewControllerWithIdentifier" for more flexibility in future. Here's come a problem :
Button being initialized
[self.playButton addTarget:self action:#selector(NavigationMethod) forControlEvents:UIControlEventTouchUpInside];
NavigateMethod
UIViewController *secondViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil]instantiateViewControllerWithIdentifier:#"SecondViewController"];
[(FirstViewController*) presentViewController:secondViewController animated:YES completion:nil];
Because everything is in UITableViewCell instead of UIViewController.
You're breaking Model View Controller methodology here... In FirstViewController you should have
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
MYCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[MYCustomTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; // might not be UITableViewCellStyleDefault
[cell.playButton addTarget:self action:#selector(navigationMethod) forControlEvents:UIControlEventTouchUpInside];
}
// all indexPath based tableViewCell changes here
return cell;
}
Now -(void)navigationMethod can go in your FirstViewController class also. Which will allow you to call
[self presentViewController:secondViewController animated:YES completion:nil];
or
[self.navigationController presentViewController:secondViewController animated:YES completion:nil];
Just to add in as well.. unrecognised selector sent to instance means in this case the method NavigationMethod is not found in your UITableViewCell subclass
In my app I am trying to navigate to a new View from a TableViewCell, But i dont know how. Could you help guys? I am using Xcode 4.6. and .xib, no storyboard. I am very new to coding so please explain it as simple as possible! Here is what i have tried, please correct me:
- (void)viewDidLoad
{
tableData = [[NSArray alloc] initWithObjects:#"aaoversikt1", #"Paul", #"George", #"Ringo", nil];
[super viewDidLoad];
UILabel *nav_title1 = [[UILabel alloc] initWithFrame:CGRectMake(60, 10, 220, 25)];
nav_title1.font = [UIFont fontWithName:#"Arial-BoldMT" size:18];
nav_title1.textColor = [UIColor whiteColor];
nav_title1.adjustsFontSizeToFitWidth = NO;
nav_title1.textAlignment = NSTextAlignmentCenter;
nav_title1.text = #"Ă…lesund";
nav_title1.backgroundColor = [UIColor clearColor];
self.navigationItem.titleView = nav_title1;
}
#pragma mark - TableView Data Source methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section;
{
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *cell = nil;
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
#pragma mark - TableView Delegate methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
AAOversiktViewController *aaoversikt1 = [[AAOversiktViewController alloc] initWithNibName:#"AAOversiktViewController" bundle:nil];
[self.navigationController pushViewController:aaoversikt1 animated:YES];
}
Thank You!
From first glance I would say that the problem lies within your [self.navigationController pushViewController] method. Have you initiated a navigation controller in your app either in the app delegate or root view controller?
If not i would recommend:
[self presentViewController:aaoversik1 animated:YES completion:NULL];
If you are wanting to push through the navigation stack so that you have a back button then I would look at implementing a UINaviationController.
Otherwise you can create a custom back button and use the same method in this post to present the root view controller (not totally recomended as using UINavigationController is much cleaner).
Let me know if this has been of any help, T
I have an rss parser as part of my app code, and it is working fine and loading the rss xml file and populating the tableview fine.
The problem is with a refresh/reload button, which does reload the rss data, but it APPENDS the new data to the table and the table just grows and grows in size.
What the behaviour should do is to clear the old table data and rebuild the table with the new data - so that the table always shows just ONE set of data and doesn't keep growing every time the reload/refresh is pressed.
The table build code is as follows:
- (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];
}
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
cell.textLabel.text = [[stories objectAtIndex: storyIndex] objectForKey: #"date"];
cell.detailTextLabel.text = [[stories objectAtIndex: storyIndex] objectForKey: #"title"];
[cell.textLabel setLineBreakMode:UILineBreakModeWordWrap];
[cell.textLabel setNumberOfLines:0];
[cell.textLabel sizeToFit];
[cell.detailTextLabel setLineBreakMode:UILineBreakModeWordWrap];
[cell.detailTextLabel setNumberOfLines:0];
[cell.detailTextLabel sizeToFit];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
And the reload/refresh button code is:
- (void)reloadRss {
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
UIBarButtonItem * barButton = [[UIBarButtonItem alloc] initWithCustomView:activityIndicator];
[[self navigationItem] setLeftBarButtonItem:barButton];
[barButton release];
[activityIndicator release];
[activityIndicator startAnimating];
[self performSelector:#selector(parseXMLFileAtURL) withObject:nil afterDelay:0];
[newsTable reloadData];
}
I have tried to solve this by adding the line:
if (stories) { [stories removeAllObjects]; }
to the reload section, which I think should work and does clear the table, but the app then crashes the app with an EXC_BAD_ACCESS.
Any ideas or suggestions greatly appreciated!
Actually, have now solved this!
Was due to "autoreleasing" elements of the array, so after clearing this out, they were invalid.
Removing autorelease and just releasing these objects in the final dealloc worked.
The Code EXC_BAD_ACCESS does mean, that you want connect at a variable that does not exists anymore.
In your code example, I can see, the problem to see at the following two lines of code:
[activityIndicator release];
[activityIndicator startAnimating];
You release the activityIdicator befor starting the Animating.
Try to release at the end of the function.
[activityIndicator startAnimating];
[self performSelector:#selector(parseXMLFileAtURL) withObject:nil afterDelay:0];
[newsTable reloadData];
[activityIndicator release];
I have a tableview with two actions in it, for the first on i use the delegate didSelectRowAtIndexPath, for the second one i would like to use an action on a button on my cell to do something else. My problem is that i don't succeed to get the indexpath ? What is the best practice to do that.
If you have added the button to the cell as,
[cell.contentView addSubview:button];
then, you can get the index path as,
- (void)onButtonTapped:(UIButton *)button {
UITableViewCell *cell = (UITableViewCell *)button.superview.superview;
NSIndexPath *indexPath = [tableView indexPathForCell:cell];
// Go ahead
}
I'm using this solution -- getting index path of cell using points
CGPoint center= [sender center];
CGPoint rootViewPoint = [[sender superview] convertPoint:center toView:_tableView1];
NSIndexPath *indexPath = [_tableView1 indexPathForRowAtPoint:rootViewPoint];
NSLog(#"%#",indexPath);
Its work perfectly
here is the full code for a custom button:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CustomCellFilter *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {cell = [[CustomCellFilter alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];}
//configure your cell here
cell.titleLabel.text = #"some title";
//add button
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
resetButton.frame = CGRectMake(40, 10, 18, 18);
[resetButton addTarget:self action:#selector(onButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
[resetButton setImage:[UIImage imageNamed:#"someimage.png"] forState:UIControlStateNormal];
[cell.contentView addSubview:myButton];
//afterwards return the cell
return cell;
- (void)onButtonTapped:(UIButton *)button {
UITableViewCell *cell = (UITableViewCell *)button.superview.superview;
NSIndexPath *indexPath = [filterTable indexPathForCell:cell];
NSLog(#"%#", indexPath);
//use indexPath here...
}
In case you are using a collection view, you can use Yogesh method, but change indexPathForRowAtPoint for indexPathForItemAtPoint like this:
CGPoint center= [sender center];
CGPoint rootViewPoint = [[sender superview] convertPoint:center toView:_tableView1];
NSIndexPath *indexPath = [_tableView1 indexPathForRowAtPoint:rootViewPoint];
NSLog(#"%#",indexPath);
In case that your button is moved or Apple changes the view hierarchy for accessory views, this method goes up the chain to look for a UITableViewCell:
- (void)tapAccessoryButton:(UIButton *)sender {
UIView *parentView = sender.superview;
// the loop should take care of any changes in the view heirarchy, whether from
// changes we make or apple makes.
while (![parentView.class isSubclassOfClass:UITableViewCell.class])
parentView = parentView.superview;
if ([parentView.class isSubclassOfClass:UITableViewCell.class]) {
UITableViewCell *cell = (UITableViewCell *) parentView;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
[self tableView:self.tableView accessoryButtonTappedForRowWithIndexPath:indexPath];
}
}
I have an app where I load a UIViewController with an UITableView. In the UITableViewCells I have a UITextField. Which I have added in the cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
if ([indexPath section] == 0) {
// Setting the cell textLabel.
[[cell textLabel] setText:[Customize objectAtIndex:indexPath.row]];
if ([indexPath row] == 0) { // Text
// Adding and customizing UITextField.
TextFieldText = [[UITextField alloc] initWithFrame:CGRectMake(160, 10, 140, 30)];
TextFieldText.placeholder = #"Random";
TextFieldText.autocorrectionType = UITextAutocorrectionTypeNo;
TextFieldText.autocapitalizationType = UITextAutocapitalizationTypeNone;
TextFieldText.returnKeyType = UIReturnKeyDone;
[cell addSubview:TextFieldText];
and so on.
The problem is that when you type in it, it is a little slow. When a letter/symbol is typed it appears in the UITextField and for a very short second the marker is still on the left side of the letter/symbol and slide across the letter/symbol. The keyboard also appears kind of slow.
Any thoughts?
Thanks in advance :)