New to ios programming so for practice I am trying to make a simple app with a playing card with it’s back on the view which you can tap to reveal the front of the card. The front of the card is different every time you tap it.
What I am trying to achieve is that when i tap the card:
- it flips and displays a random card,
- have a label that increments by 1 every time the card is flipped
I am done with the second requirement but I can’t seem to get the first one right. I have 3 models(Card, Deck, PlayingCard)
My Deck model is responsible for randomising the cards and here are the codes.
Deck.h
#import <Foundation/Foundation.h>
#import "Card.h"
@interface Deck : NSObject
- (void)addCard:(Card *)card atTop:(BOOL)atTop;
- (Card *)drawRandomCard;
@end
Deck.m
#import "Deck.h"
@interface Deck()
@property (strong, nonatomic) NSMutableArray *cards;
@end
@implementation Deck
-(NSMutableArray *)cards
{
if(!_cards) _cards =[[NSMutableArray alloc] init];
return _cards;
}
- (void)addCard:(Card *)card atTop:(BOOL)atTop
{
if(card){
if(atTop){
[self.cards insertObject:card atIndex:0];
}
else
{
[self.cards addObject:card];
}
}
}
- (Card *)drawRandomCard
{
Card *randomCard = nil;
if(self.cards.count){
unsigned index = arc4random() % self.cards.count;
randomCard = self.cards[index];
[self.cards removeObjectAtIndex:index];
}
return randomCard;
}
@end
My PlayingCard basically describes the contents of a Card. for eg. Jack of Hearts, 2 of Diamonds where Jack would be the “rank” of the card and “hearts” would be the suit of the card which together form the contents of the card.
PlayingCard.h
#import <Foundation/Foundation.h>
#import "Card.h"
@interface PlayingCard : NSObject
@property (strong, nonatomic) NSString *suit;
@property (nonatomic) NSUInteger rank;
+ (NSArray *) validSuits;
+ (NSUInteger) maxRank;
- (NSString *)contents;
@end
PlayingCard.m
#import "PlayingCard.h"
@implementation PlayingCard
- (NSString *)contents
{
NSArray *rankStrings = [PlayingCard rankStrings];
return [rankStrings[self.rank] stringByAppendingString:self.suit];
}
@synthesize suit = _suit;
+(NSArray *)validSuits{
return @[@"♥", @"♦", @"♠", @"♣"] ;
}
+(NSArray *)rankStrings{
return @[@ "?", @"A", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9",@"10", @"J", @"Q", @"K"];
}
-(void)setSuit:(NSString *)suit
{
if([[PlayingCard validSuits] containsObject:suit]){
_suit = suit;
}
}
-(NSString *)suit{
return _suit ? _suit: @"?";
}
+ (NSUInteger)maxRank {
return [self rankStrings].count-1;
}
-(void)setRank:(NSUInteger)rank{
if(rank <= [PlayingCard maxRank]) {
_rank = rank;
}
}
@end
Finally my ViewController.m
#import "CardGameViewController.h"
#import "Card.h"
#import "Deck.h"
#import "PlayingCard.h"
@interface CardGameViewController ()
@property (weak, nonatomic) IBOutlet UILabel *flipsLabel;
@property (nonatomic) int flipCount;
@property (nonatomic) NSString *title;
@property (weak, nonatomic) IBOutlet UIButton *cardRandom;
@end
@implementation CardGameViewController
- (void)setFlipCount:(int)flipCount
{
_flipCount = flipCount;
self.flipsLabel.text = [NSString stringWithFormat:@" Flips:%d", self.flipCount ];
}
- (IBAction)flipCard:(UIButton *)sender
{
if(sender.isSelected) {
sender.selected = NO;
self.flipCount ++;
}
else{
sender.selected = YES;
self.flipCount ++;
}
}
@end
I researched about this and i found that I should probably use
- (void)setTitle:(NSString *)title forState:(UIControlState)state
where the state will be UIControlStateSelected because the front of the card containing the contents is the selected content of the button but I dont know how to set the title according to the random card content developed by my model.
Lets assume you have a property of the class Deck (called cardDeck) in your CardGameViewController, and you have already populated that property with cards using addCard method.
Now when the user taps flip button, you should do something like this ::
Hope this helps
PS :: drawRandomCard method has a return type “Card”, it seems it should be “PlayingCard”, or the PlayingCard class should be named Card.