CATransaction completion block never fires
Asked Answered
S

1

9

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.

Shipley answered 14/12, 2014 at 14:7 Comment(4)
Can you let us know where / when you call this, because it is working on my side.Kumquat
It is called in response to a button pressShipley
Can you update your question with the details?Kumquat
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.Shipley
S
16

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];
});
Shipley answered 14/12, 2014 at 17:1 Comment(4)
thanks for including your solution. I had a CATransaction block with a completion block that has been working forever. At some point in my latest release cycle it just.... stopped being called. Wrapping in dispatch_async appears to have fixed it. (though it pains me to do it without understanding why it fixed it!)Offal
oh my god, I have no idea why this works, but it works on my end too....Bitumen
This https://mcmap.net/q/1173127/-uiview-animatewithduration-never-reaches-completion-block explains a bit further why that may be happeningBitumen
My guess is that [CATransaction setCompletionBlock:] enqueues some work on the main queue that takes care of setting the completion, so by wrapping popViewControllerAnimated: in a dispatch async we’re waiting for that work to complete before triggering the animation. That has to be why it works.Bitumen

© 2022 - 2024 — McMap. All rights reserved.