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 <ippo...@me.com> 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 (Cocoa-dev@lists.apple.com)
> 
> 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:
> https://lists.apple.com/mailman/options/cocoa-dev/agrosam%40onlinehome.de
> 
> This email sent to agro...@onlinehome.de


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to