EDIT: Ok, so i figured out how to remedy my original problem, but i’m not sure if this is the best way.
My new question is, say I have a subclass of UITableViewCell with the following property declaration in the header:
@property (nonatomic, retain) IBOutlet UILabel *levelLabel;
This is connected in IB. Is it ok to not release this in dealloc, and not release it at all? This is the only way I can figure out to get it to work, without giving me an exc_bad_access error. Before, it called dealloc when the tableviewcell went off the screen but then it still needed it. where do i release stuff, or does it take care of that for me?
Original Title: Memory leak in UITableView and exc_bad_access
Ok, I am confused. I was following along with this tutorial online making custom UITableViewCells. I made one, and i did everything like the tutorial told me. My UITableViewCell subclass contains 3 UILabels and 3 UIButtons, and has all of them defined as properties and connected in IB. I need them to be available to the class because i need to know when the buttons are pressed and be able to change the text. When I run the app, i start scrolling and after a few seconds it crashes, with exc_bad_access in main (no output in the console). But when I run the app in instruments with NSZombieEnabled, it does not crash at all, and runs just fine. However, since instruments shows you the allocations, i can see them going up very quickly, especially as I scroll. I dont know if this is all allocations, or if these are being released, but still it seems too fast.
Here is PointCoordinatesCell.h (my custom cell):
#import <UIKit/UIKit.h>
@interface PointCoordinatesCell : UITableViewCell
@property (nonatomic, retain) IBOutlet UILabel *levelLabelLabel;
@property (nonatomic, retain) IBOutlet UILabel *levelLabel;
@property (nonatomic, retain) IBOutlet UILabel *levelDescriptionLabel;
@property (nonatomic, retain) IBOutlet UIButton *beginningButton;
@property (nonatomic, retain) IBOutlet UIButton *developingButton;
@property (nonatomic, retain) IBOutlet UIButton *secureButton;
@end
PointCoordinatesCell.m:
#import "PointCoordinatesCell.h"
@implementation PointCoordinatesCell
@synthesize levelLabel, levelLabelLabel, levelDescriptionLabel, beginningButton, developingButton, secureButton;
- (void)dealloc{
[super dealloc];
[levelLabel release];
[levelLabelLabel release];
[levelDescriptionLabel release];
[beginningButton release];
[developingButton release];
[secureButton release];
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
@end
RootViewController.h has nothing in it other than a class declaration and standard imports. No variables or methods defined. It subclasses UITableViewController.
RootViewController.m:
#import "RootViewController.h"
#import "StatesAppDelegate.h"
#import "PointCoordinatesCell.h"
@implementation RootViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 50;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
return 293;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"PointCoordinatesCell";
PointCoordinatesCell *cell = (PointCoordinatesCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"PointCoordinatesCell" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (PointCoordinatesCell *) currentObject;
break;
}
}
}
//cell.capitalLabel.text = [capitals objectAtIndex:indexPath.row];
//cell.stateLabel.text = [states objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
// AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil];
// [self.navigationController pushViewController:anotherViewController];
// [anotherViewController release];
}
- (void)dealloc {
[super dealloc];
}
@end
It seems you are doing some complicated casting in your
cellForRowAtIndexPathmethod. I do not think this is necessary. It does not seem logical to me to check for an object of classUITableViewCelland then cast it into a custom cell. The cell in your nib should already be a custom cell.In the Apple sample the loading of the cell is much more straight forward. You link your custom cell to an
IBOutletin your view controller and then do this: