1

I'm trying to return a value in a method that contains an animation block. The code I have below works perfectly fine, but it seems like there should be a better or cleaner way to do it. Is there a better way to do this?

 + (BOOL) flipImageAndTextForView:(UIView *) viewFlipImageAndText IsImageDisplayed:(BOOL) imageFlipDisplayed  flipTextView:(UITextView *) textViewDonate flipImage: (UIImageView *)pictureImage{

            __block BOOL tempBool;

        [UIView transitionWithView:viewFlipImageAndText
                          duration:0.3f
                           options:UIViewAnimationOptionTransitionFlipFromLeft
                        animations:^(void) {
                            if (imageFlipDisplayed)
                            {
                                [viewFlipImageAndText bringSubviewToFront:textViewDonate];
                                tempBool = FALSE;
                            }
                            else
                            {
                                [viewFlipImageAndText bringSubviewToFront:pictureImage];
                                tempBool = TRUE;                            
                            }
                        }
                        completion:^(BOOL finished) {
                            NSLog(@"Done!");
                        }];

        if(tempBool)
        {
            return TRUE;
        }
        else{
            return FALSE;
        }

    }
AaronG
  • 532
  • 1
  • 7
  • 18
  • 1
    when you're talking about async code and "returning data" you may be thinking about it wrong. It's not a call return pattern - it's a go do some work and when you're done, run this code pattern. Torrey is correct you have a race condition. See the answer and sub links: http://stackoverflow.com/questions/7290931/gcd-threads-program-flow-and-ui-updating/7291056#7291056 – bryanmac Sep 07 '12 at 00:50
  • Thanks, you nailed it, I wasn't thinking about the pattern correctly. – AaronG Sep 07 '12 at 01:09

2 Answers2

2

Your code has a race condition because you can't guarantee that tempBool will be set correctly before your flipImageAndTextForView:... method returns. transitionWithView:duration:options:animations:completion: does not block. In any case the following lines:

    if(tempBool)
    {
        return TRUE;
    }
    else{
        return FALSE;
    }

should have just been replaced with:

    return tempBool;

If it works the way you wrote it and not the second way, that is just another symptom of the inherent race condition here.

The best thing to do is to not structure your code like this at all. Either test imageFlipDisplayed outside the animation block altogether or else use the completion block of transitionWithView:duration:options:animations:completion: to send a message to somewhere else with the information you need when the animation is complete.

torrey.lyons
  • 5,519
  • 1
  • 23
  • 30
  • 1
    +1 - I think the op asking about "returning data" and async is not thinking about the pattern correctly. – bryanmac Sep 07 '12 at 00:52
  • Yes, this is exactly what I wanted. I knew it worked but it wasn't the right way to do it. Just what I needed to start thinking about this the right way. Thank you very much for your answer. – AaronG Sep 07 '12 at 01:07
0

The problem is that the value is only set when the animation starts, which is probably the next iteration of the runLoop. You could make the same text before the UIView animation call, which seems like a reasonable thing to do, or you could have the completion block message back to something.

David H
  • 40,852
  • 12
  • 92
  • 138