Fixing UIAnimator removeAnimationsForTarget crash
You tested your app on the Simulator and everything is fine. You’ve moved it to the iPhone, and when you reach a certain TableViewController your app crashes with the following message: [UIAnimator removeAnimationsForTarget:]. How would you approach this issue? Using common sense, try to set a breakpoint in each function from your TableViewController, then step through them to see in/after which function does the crash happens. In my case, the responsible code was found in the function:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
It entered this function, once for each cell, but it crashed after exiting. As a new iOS developer, I was trying to set a couple of different UITableViewCell in one TableViewController. Here is a sample of the code I was using in the first version:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Setting a generic cell
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]
autorelease];
}
// ... Other code
// Replace generic cell with custom cell
if(objectType == CMMUItemViewSectionSummary){
NSArray *topLevelObjects = [[NSBundle mainBundle]
loadNibNamed:@"SummaryCell"
owner:nil
options:nil];
for(id currentObject in topLevelObjects){
if([currentObject isKindOfClass:[SummaryCell class]]){
cell = (SummaryCell *) currentObject;
break;
}
}
cell.summaryData = summaryData;
} else if(objectType == CMMUItemViewSectionStatuses){
NSArray *topLevelObjects = [[NSBundle mainBundle]
loadNibNamed:@"ItemStatusCell"
owner:nil
options:nil];
for(id currentObject in topLevelObjects){
if([currentObject isKindOfClass:[ItemStatusCell class]]){
cell = (ItemStatusCell *) currentObject;
break;
}
}
cell.statusesData = statusesData;
} else {
cell.textLabel.text = someDefaultData;
}
// Return the cell
return cell;
}
As you can see in the above code, after I was getting a generic cell, I would try to replace it with a custom cell. I guess that somewhere after tableView:cellForRowAtIndexPath: some other piece of code was trying to cleanup the unused cells. Figuring this, it was pretty easy to get it fixed. Using the same sample code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = @"Cell"; //Generic identifier
UITableViewCell *cell;
// Other code ...
CellIdentifier = [NSString stringWithFormat:@"Cell%d", objectType]; //cell of my object type
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(objectType == CMMUItemViewSectionSummary){
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"SummaryCell"
owner:nil
options:nil];
for(id currentObject in topLevelObjects){
if([currentObject isKindOfClass:[SummaryCell class]]){
cell = (SummaryCell *) currentObject;
break;
}
}
}
cell.summaryData = summaryData;
} else if(objectType == CMMUItemViewSectionStatuses){
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle]
loadNibNamed:@"ItemStatusCell"
owner:nil
options:nil];
for(id currentObject in topLevelObjects){
if([currentObject isKindOfClass:[ItemStatusCell class]]){
cell = (ItemStatusCell *) currentObject;
break;
}
}
}
cell.statusesData = statusesData;
}
if(cell == nil){
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier]
autorelease];
}
return cell;
}
Even if is not the optimal way to use custom TableViewCells, it solves the crash problem. Improvements and suggestions, are welcomed.