Re: Block gets NULL-ified when animation completes
Re: Block gets NULL-ified when animation completes
- Subject: Re: Block gets NULL-ified when animation completes
- From: Andreas Grosam <email@hidden>
- Date: Thu, 15 Aug 2013 11:51:22 +0200
The collection view will very likely have corresponding ivars for the animation block and its completion handler. If that's the case, it should (shall) create a copy of the anonymous animation (updates) and completion block when receiving them in `performBatchUpdate:completion:`.
Now, `finish` is an "imported field" of the anonymous completion handler. The copy operation of the anonymous completion handler will cause the block `finish` to be copied as well. Since the outer block lives on the heap, the imported fields of `finish` will live there, too. Effectively, imported fields will be "copied" into the storage area of the outermost block.
It seems to me, that block `finish` should have a ref count of +1 within the anonymous completion handler.
Vlad, could you please verify your observations and possibly create a simple test class mimicking the behavior of the collection view (no animation, just a dummy async method), e.g.
dispatch_block_t completion = ^{
NSLog(@"invoking completion");
};
dispatch_block_t updates = ^{
NSLog(@"invoking updates");
};
dispatch_block_t finish = ^{
NSLog(@"invoking finish");
if (completion) {
completion();
}
};
if (animated) {
self.testClass performDummyMethod:^{
updates();
} completion:^(BOOL finished) {
finish();
}];
When TestClass actually makes copies of the block when setting its ivars `_updates` and `_completion`, it should work (IMO).
See also: "Block Implementation Specification" <http://clang.llvm.org/docs/Block-ABI-Apple.html> (especially, "Imported const copy of Block reference).
Andreas
On 09.08.2013, at 16:57, Vlad Alekseev <email@hidden> wrote:
> Hey!
>
> I have a method where I update my collection view's layout parameter and want to have a completion block invoked when animation completes:
>
> - (void)transitionAnimated:(BOOL)animated completion:(dispatch_block_t)completion
> {
> dispatch_block_t updates = ^{
> self.layout.maximumScale = self.maximumScale;
> };
>
> dispatch_block_t finish = ^{
> if (completion) {
> completion();
> }
> };
>
> if (animated) {
> self.collectionView.userInteractionEnabled = NO;
> [self.collectionView performBatchUpdates:^{
> updates();
> } completion:^(BOOL finished) {
> self.collectionView.userInteractionEnabled = YES;
> finish();
> }];
> }
> else {
> updates();
> [self.layout invalidateLayout];
> finish();
> }
> }
>
> It works as expected if collection view contains some items. But it crashes if collection view is empty. And it crashes here:
>
> } completion:^(BOOL finished) {
> self.collectionView.userInteractionEnabled = YES;
> finish(); // ---- CRASH because finish == NULL
> }];
>
> Debugger says that finish is nil:
>
> (lldb) p finish
> (dispatch_block_t) $1 = <parent is NULL>
>
> What is going on with that block? Any ideas why it gets NULL-ified?
> _______________________________________________
>
> Cocoa-dev mailing list (email@hidden)
>
> Please do not post admin requests or moderator comments to the list.
> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden