3

I'm writing a little card game where 4 cards are dealt to the screen and the user can tap each card to reveal (and again to hide) it.

Each card-front and card-back are stored in image views. A UIButton catches the user tap and should flip the card over.

I've added front and back of the card as subviews to a container view and I use the method UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight for the animation.

Please see the code below, I've removed the handling of the 4 different cards in the methods below for the sake of simplification & readability. Also I've replaced some array/filename-juggling for the cards with static image-names for front and back here.

The strange thing with this code now is the sometimes it works as expected 10 times in a row (i.e. the flipping animation is shown) but sometimes no animation is shown at all (i.e. the other card side is shown but without the flipping.). Then it's the other way round: Sometimes the card is shown without any animation for 7 or 8 times then suddenly the flipping-animation is shown. It's driving me nuts as I can't see the reason for this strange behaviour. Do you have any idea? I'm building for iOS 8 to iOS 10.

From the .h file:

@interface GameViewController : UIViewController 
{
    UIImageView             *cardback1;
    UIImageView             *cardfront1;
    UIView                  *containerView;
    BOOL                    c1Flipped;
    // much more...
}

And from the .m file:

-(void)flipCardButtonClicked:(id)sender
{
    containerView = [[UIView alloc] initWithFrame: CGRectMake(25,420,220,300)];
    [self.view addSubview:containerView];       

    c1Flipped = !c1Flipped;

    cardback1 = [[UIImageView alloc] initWithFrame: CGRectMake(0,0,220,300)];
    cardfront1 = [[UIImageView alloc] initWithFrame: CGRectMake(0,0,220,300)];

    if (c1Flipped)       
    {
        cardback1.image = [UIImage imageNamed:@"backside.png"];
        cardfront1.image = [UIImage imageNamed:@"frontside.png"];
    }
    else 
    {
        cardback1.image = [UIImage imageNamed:@"frontside.png"];
        cardfront1.image = [UIImage imageNamed:@"backside.png"];
    }

    [containerView addSubview:cardfront1];
    [containerView addSubview:cardback1];
    [cardfront1 release];
    [cardback1 release];

    [self performSelector:@selector(flipSingleCard) withObject:nil afterDelay:0.0];
}

-(void)flipSingleCard
{
    [containerView.layer removeAllAnimations]; 
    [UIView beginAnimations:@"cardFlipping" context:self];  
    [UIView setAnimationBeginsFromCurrentState:YES];   
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(flipDidStop:finished:context:)];
    [UIView setAnimationDuration:0.5];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:containerView cache:YES];
    [containerView exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
    [UIView commitAnimations];
}

-(void)flipDidStop:(NSString*)animationID finished:(BOOL)finished context:(void *)context 
{
    [containerView removeFromSuperview];
    [containerView release];
}
Bryan
  • 14,756
  • 10
  • 70
  • 125
SpaceAce
  • 43
  • 4

2 Answers2

1

My guess is that [self performSelector:@selector(flipSingleCard) withObject:nil afterDelay:0.0]; is the culprit. Seems like this could be a timing issue. Have you tried adding an actual delay to this? Say...0.1? I believe that doing this could fix this, OR just simply calling the method directly instead of using performSelector.

BHendricks
  • 4,423
  • 6
  • 32
  • 59
  • Thanks for your thoughts but because animations are asynchronous I thought that's the main reason for using a selector instead of calling the method directly (?) The setAnimationDidStopSelector method should not get called before the actual animation did stop. – SpaceAce Oct 12 '16 at 17:04
  • I don't see how being asynchronous has any effect on using a selector vs. direct method call. You're essentially doing the same thing either way...have you tried adding an actual delay? – BHendricks Oct 12 '16 at 17:09
  • Sorry, I was looking at the wrong selector. I will try the change with the performSelector and post the outcome, thanks again. Sidenote: Is there an option to edit/delete my own comments here? – SpaceAce Oct 12 '16 at 17:09
  • Adding a delay of 0.1 in the performSelector actually helped. – SpaceAce Oct 12 '16 at 17:21
1

Looks like it indeed was a timing issue as suspected by BHendricks. Adding a 0.1 delay solved the problem. Thanks a lot.

SpaceAce
  • 43
  • 4