8
votes

How come the completion block for this CATransaction never fires?

[CATransaction begin];
[CATransaction setCompletionBlock:^{
    // table animation has finished
    NSLog(@"why does this section never execute?");
}];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.currentFeedItems.count inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
[CATransaction commit];

The tableview animation works, but the completion block is never executed. The Apple documentation says that the completion block is guaranteed to execute.

1
Can you let us know where / when you call this, because it is working on my side. - Unheilig
It is called in response to a button press - Darren
Can you update your question with the details? - Unheilig
I originally set up a button in a table cell and used a delegate to get the controller to call the above code. Didn't work. So then, thinking it may have something to do with the thread it was executing on I wrapped the above code in a dispatch_async(dispatch_get_main_queue()... block. Didn't work. So then, I instead used a notification to fire the above code. Didn't work. So... finally I tried putting the above code in a simple method on the controller itself and, when didSelectRowAtIndexPath fired, calling this method. That didn't work either. - Darren

1 Answers

15
votes

Oh boy, this was so obscure I'm actually amazed I found the problem.

The cell that was being reloaded contains a UIActivityIndicatorView, which worked fine. When the cell reloads it implicitly redraws the table cell and a startAnimating call happens within that process in the table cell. Somehow that startAnimating call interferes with the CATransaction completion block.

When I wrap the startAnimating call in a dispatch_async block, the problem goes away:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.loadingInd startAnimating];
});