Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

Why does this reloadData crash my program?

Can anyone help me figure out why [tableView reloadData] is crashing my program? I have a grouped tableView where I want to allow the user to reorder rows. Each of the rows is dynamically numbered in cellForRowAtIndexPath, so when the cell draws the rows are consecutively numbered. Whenever the user makes a change to the list order such as from:

1. Name A
2. Name B
3. Name C

to: (switch 1 & 3)

3. Name C
2. Name B
1. Name A

I want it to say

1. Name C
2. Name B
3. Name A

Here is the code, but I get * Terminating app due to uncaught exception 'NSRangeException', reason: ' * -[NSCFArray objectAtIndex:]: index (1) beyond bounds (1)'

Here is the Code:


- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
if (fromIndexPath.section == 0) {
NSDictionary *currentName =[[[bNameChoices objectAtIndex:fromIndexPath.row] retain] autorelease];
[bNameChoices removeObjectAtIndex:fromIndexPath.row];
[bNameChoices insertObject:currentName atIndex:toIndexPath.row];
} else if (fromIndexPath.section == 1) {
NSDictionary *currentName =[[[gNameChoices objectAtIndex:fromIndexPath.row] retain] autorelease];
[gNameChoices removeObjectAtIndex:fromIndexPath.row];
[gNameChoices insertObject:currentName atIndex:toIndexPath.row];
}
[tableView reloadData];
}


Any help on this would be appreciated!

iMac 24" 2.8g, iPhone 16g Black, 2.1, iPod Touch 16g, Mac OS X (10.5.5)

Posted on Oct 14, 2008 7:06 PM

Reply
18 replies

Oct 14, 2008 7:30 PM in response to RickMaddy

Why not the retain? Calling removeObjectAtIndex: will also call release on the object. After adding it back in, you should call release on it as the insertObject:atIndex: will call retain. A better option might be to insert it in the new location before removing it from the old location.

I've done this myself and build a little framework to do it (moves, drags, drops, deletes, undos) reliably, but it sure wasn't easy!

Oct 14, 2008 7:39 PM in response to etresoft

I realize the 'remove' will release it but the 'insert' will retain it. Is it possible for the object to get deallocated between the two calls? If so then the retain would be needed. But then a call to release would be needed after the insert, right?

My answer was based on an assumption that the object couldn't get deallocated between the remove and insert calls. Please let me know if this is an invalid assumption.

Oct 15, 2008 12:08 AM in response to gpmoore

tableView:moveRowAtIndexPath:toIndexPath: won't do anything unless you call it.

So, what was the exact call that you used?

What was the complete traceback at the time of the crash? That is, where did the crash occur? What function called the function in which the crash occurred? What function called the function that called the function in which the crash occurred? And so on... The console output will tell you this. The crash is unlikely to be in reloadData: it is probably either in tableView:moveRowAtIndexPath:toIndexPath: or in one of your functions that are called by reloadData.

How many elements are there in bNameChoices/gNameChoices before tableView:moveRowAtIndexPath:toIndexPath: does its work? How many elements are there afterwards? What are they, and what order are they in? You can answer all these questions by putting lots of NSLog calls into your code, to write information to the console.

Oct 15, 2008 6:55 AM in response to RickMaddy

It is just that the retain, followed by autorelease is strange. Given that particular setup, you should be able to remove and then re-insert. However, I have no idea what is going on with the autorelease pool. It is one thing to take an autoreleased object and do your own retains and releases on it in your own memory management, but it is something else to take manually managed memory and put it into some random autorelease pool.

Oct 15, 2008 12:08 PM in response to RickMaddy

Ok, I think I will try that and see what happens.

I found a work around which I am a bit embarrassed by but it works (I hate cheating like this but I didn't want to waste time):

in place of reloadData:

//....
[NSTimer scheduledTimerWithTimeInterval:(0.35) target:self selector:@selector(refreshTable) userInfo:nil repeats:NO];
//....



- (void)refreshTable {
[settingsTableView reloadData];
}


I experimented with different time intervals -- anything shorter than 0.35 crashes the program and anything much longer gives a "lagging feeling" once the user moves rows.

Message was edited by: gpmoore

Message was edited

Oct 15, 2008 2:34 PM in response to gpmoore

gpmoore wrote:
I found a work around which I am a bit embarrassed by but it works (I hate cheating like this but I didn't want to waste time):


Doing it correctly is not a waste of time. I suspect that you have other things going on that are causing your crash. How far do you want to go with this program? If you want to support drag-n-drop and other fancy things then you'll have to get this resolved.

There has been some side discussion here that you may or may not have seen. I don't know what is going on with your autorelease. For all I know you are giving your object to some random autorelease pool from the context of whomever is calling this delegate function.

Full support of drag and drop can be complicated. Essentially, what I do is this:
1) Remove all selected row objects (which may be a discontiguous set) and move them to a new array.
2) Find the insertion point. You will need to do some calculations to find where it will be.
3) Move all the objects from the temp array into the new location.

Here is an example straight from my code:

// Move rows to a new row.
- (void) moveRows: (NSIndexSet *) rows toRow: (unsigned int) row
{
// Get an array of the rows I'll be moving.
NSArray * movedRows = [myData objectsAtIndexes: rows];

// Remove the rows from the list.
[myData removeObjectsAtIndexes: rows];
unsigned int offset = 0;

// Now that I've removed the rows. I need to calculate the new
// insert location, taking into account rows that I just removed.
for(unsigned int i = [rows firstIndex]; i != NSNotFound;
i = [rows indexGreaterThanIndex: i])
if(i < row)
++offset;

// Build a new set of rows, taking the offset into account.
NSIndexSet * newRows =
[NSIndexSet indexSetWithIndexesInRange:
NSMakeRange(row - offset, [rows count])];

// Now put the rows where they need to be.
[myData insertObjects: movedRows atIndexes: newRows];
// Redisplay the table.
[myTableView reloadData];

// Select the new rows.
[myTableView selectRowIndexes: newRows byExtendingSelection: NO];

if(myUndoManager)
// Allow this operation to be undone.
[[myUndoManager prepareWithInvocationTarget: self]
moveRowsAtRow: row - offset toRows: rows];
// Update the change counter.
if(myDocument)
[myDocument updateChangeCount:
([myUndoManager isUndoing] ? NSChangeUndone : NSChangeDone)];
}

Oct 15, 2008 6:50 PM in response to etresoft

I really appreciate your input! I think your question about what is really happening with autorelease is a good one. I tried removing the autorelease and then both the retain/autorelease and neither seemed to have any effect on the [tableView reloadData] --> it still crashes because the index of the array is out of range I think.

Oct 16, 2008 4:52 PM in response to Nugae

I'm having a similar problem - I get that same exception if I reload the table data from tableView:moveRowAtIndexPath:toIndexPath:.

I can guarantee that it's not an issue with my data model, because it happens even in situations in which the "from" and "to" rows are the same, and my "move" logic short-circuits in that case and doesn't touch anything.

Basically, it just seems like a tableView doesn't like to be reloaded as it's moving things. The 0.35 second delay that was reported making things better - I wonder if that has something to do with the animation that's going on...

Oct 16, 2008 8:52 PM in response to kdhunter

It must. I was worried the delay would need to be longer in on the device (as opposed to the Simulator) but it works fine. I wouldn't even fool with this if I didn't want the rows numbered (but I do). So even though I'd like to fiddle with this for a few more nights and figure out the right way to fix this problem, I really need to get this #)(*ing app done already and into the ever-lengthening approval queue!

Why does this reloadData crash my program?

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.