Question

I am following through the Stanford iOS class and have a bit of a design question. In the class we are making a card matching game that has some 20 cards on screen or so. I recently made the cards UIViews so I could draw them properly.

I gave them each a method tap that will swap faceUp to YES/NO, thus flipping the cards. I add the gesture recognizer to each in my ViewController and it works. The individual cards know when they're touched and flip.

However, I need to know in my ViewController that a cardView has been touched... and which one.

How/what ways do I have to do this? Can I broadcast something in my View that the ViewController will listen for? Can I have my viewController handle that taps (but is there a way to get the sending view if I do this?) I apologize if this is really base, but I'm new to iOS and would like to not learn by patching and implementing a broken MVC pattern.

EDIT: Just for information, this is my final implementation.

Each CardView has a tap recognizer on it. When a tap is recognized it calls:

- (void)cardTapped:(UIGestureRecognizer *)gesture
{
    UIView *view = [gesture view]; // This method is what I was looking for. 
    if ([view isKindOfClass:[PlayingCardView class]]) {
        PlayingCardView *playingCardView = (PlayingCardView *)view;
        [playingCardView flip];  // flips card
        // Game code
        if (!self.game.hasStarted) {
            [self startGame];
        }
        int cardIndex = [self.cardViews indexOfObject:playingCardView];
        [self.game chooseCardAtIndex:cardIndex];
        [self updateUI];
    }
}
Was it helpful?

Solution

The tag property will tell you which view has been tapped. Set the proper tag when you create your view and in your action method that's been triggered on tap you can call a delegate method that will notify your delegate about which view has been tapped. Make your viewcontroller has the delegate and it will received the notification.

// your target method will look like this:
- (void) didTap:(id)sender {

   //... your code that handle flipping the card

   [self.delegate didTapOnCard:self]; // where delegate is your view controller

}

OTHER TIPS

You can use touchesBegan method to detect which view was tapped.

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    NSLog(@"%d", [touch view].tag); // Considering you have set tags for your UIViews.. 

if([touch view] == cardView1) // Considering you have a view as cardView1
{
    NSLog(@"cardView1 is tapped");
}

}

In your UIView card class add

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)e {
    UITouch *touch = [touches anyObject];

    if ([self pointInside:[touch locationInView:self] withEvent:nil]) {
        [self touchesCancelled:touches withEvent:e];
        // Add your card flipping code here
    }
}

The broadcast approach: in your UIView's tap method, send a notification:

[[NSNotificationCenter defaultCenter] postNotificationName:@"cardTapped" object:self userInfo:@{ @"card": @(self.cardId), @"faceUp": @(self.faceup) }];

and in your ViewController subscribe to that notification:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cardTapped:) name:@"cardTapped" object:nil];

and implement

-(void)cardTapped:(NSNotification*)notification
{
    int card = [[notification.userInfo objectForKey:@"card"] intValue];
    BOOL faceUp = [[notification.userInfo objectForKey:@"faceUp"] boolValue];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top