PDA

View Full Version : UITableViewController crashing when cell is reloaded




cmezak
Jul 23, 2008, 09:09 AM
Hey all,

I'm working with an app that has a tab bar controller toggling between two navigation controllers. These navigation controllers each contain an instance of the same subclass of UITableViewController. The instances differ only by an instance variable that determines what data the controllers will display in their tableViews.

My problem is that, in ONE of these views, the app crashes when a cell that has scrolled offscreen is about to return to the view. Through NSLogs, I know that the app successfully gets to the end of the cellForRowAtIndexPath method before crashing. What I don't understand is why this should happen to one tableview but not the other, when the code that governs them is virtually identical.

The one that crashes is the first view that is loaded in the app, but other than that I can't think of a difference that would be related to this problem.

any ideas?

Thank you!

Charie



cmezak
Jul 23, 2008, 09:22 AM
Well, by changing the first tableview to display the same data as the second one, the app works. Why should this be? When the application loads, the data loads up fine for the first view. It's only when it attempts to reload it that the app crashes.

I've just implemented data loading from sqlite3, so I suspect that I've done something weird in there that is corrupting the data that I load in a way that allows it to be read once, but not again . . . weird.

cmezak
Jul 23, 2008, 09:35 AM
I've found the important difference:

The data in the second tableview is gotten from a method in the data objects that creates a mutable string, puts two of the object's instance strings into it, and return it.

The data in the one that is crashing is a direct call to a get method of a string that is a property of the data object.

I don't know why this makes a difference, but I think this is it. Somehow, the data in the object isn't able to be called again after the cell disappears. Why is this?

cmezak
Jul 23, 2008, 09:41 AM
Here is how I am getting the data objects info from the database:

self.infoString = [NSString stringWithUTF8String:(char *)sqlite3_column_text(init_statement, 0)];

If I add a copy command like this:

self.infoString = [[NSString stringWithUTF8String:(char *)sqlite3_column_text(init_statement, 0)] copy];

Then the cell can be reloaded after it has gone offscreen, but only ONCE.

There's something wrong with the way I am storing the string in to data object, right? My property statement for this string is (nonatomic, copy). This is what is used in the Books SQL example code.

Whats going on here?


Thanks!

Charlie

cmezak
Jul 23, 2008, 10:18 AM
I just found a solution, although I think I need to do some reading to understand why it is needed. It is in the cellForRowAtIndexPath

Here is the code for that method:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyIdentifier"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"MyIdentifier"] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
NSLog(@"setting birdlist cell text");
// Get the object to display and set the value in the cell
Bird *itemAtIndex = (Bird *)[dataController objectInListAtIndex:indexPath.row :key];

NSString * cellText = nil;

//get the name according to the ordering rule (the key)
switch (key) {
case 0:
cellText = [[itemAtIndex cName] copy];
NSLog(@"creating cell for:");
NSLog(cellText);
break;
case 1:
cellText = [[itemAtIndex sName] copy];
NSLog(@"creating cell for:");
NSLog(cellText);
break;
default:
break;
}

cell.text = cellText;
[cellText release];

NSLog(@"cell ready for display");
return cell;
}

The two "copy" messages send to the itemAtIndex objects are what fixed the problem. I supposed that what was happening is that, by setting cellText to point to those instance strings, I released them when I release cellText.

My question now is, should I be copying to a new string and releasing it like this? Or should I just get rid of the [cellText release] message? I have a feeling that the latter is the appropriate solution. Please let me know!

Thanks!
Charlie

tmadsen
Feb 25, 2009, 07:05 AM
Hi cmezak, I registered just for you, since you solved my similar problem, thank you. My problem was that I have a person object, that has a name property, I want the table view to be a list of names. So I had a

@property (nonatomic, assign) NSString *name

but instead that should have been
@property(nonatomic, copy) NSString *name

or at least that seems to work, which is good enough for now. I think you're right about the release thing, sp what you're seeing instead of what you're expecting is what happens to be in the memory that the pointer points to after the property was released.

tmadsen
Feb 25, 2009, 07:10 AM
@property (nonatomic, retain) NSString *name works as well, that way the retain count bumps up before it bumbs down upon the release :)

cmezak
Feb 25, 2009, 09:32 AM
Yeah, I think the problem was that I was releasing the object's property like this:


NSString *objectName = [object name];

cell.text = objectName;

[objectName release];


Just looking at this makes me wince. I've learned a lot about memory management since then!

[edit: just to be clear. The reason this is incorrect is that this block of code doesn't "own" the object's name property. Unless I were to do create a new copy of the property string in memory, there's no need to release it. By releasing it the way I did, I basically just told the object to forget its name. Bad!]

- Charlie