Reputation: 2489
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:
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.
Upvotes: 0
Views: 867
Reputation: 808
You aren't initializing your playing card deck. Your ViewController.m file should look like this (I also reset the deck once all cards have been shown in the flipCard method):
#import "CardViewViewController.h"
#import "PlayingCardDeck.h"
@interface CardViewViewController ()
@property (weak, nonatomic) IBOutlet UILabel *flipsLabel;
@property (nonatomic) int flipCount;
@property (nonatomic) PlayingCardDeck *myDeck;
@end
@implementation CardViewViewController
-(PlayingCardDeck *)myDeck
{
if(!_myDeck) _myDeck=[[PlayingCardDeck alloc] init];
return _myDeck;
}
-(void)setFlipCount:(int)flipCount
{
_flipCount= (int) flipCount;
self.flipsLabel.text=[NSString stringWithFormat:@"Flips: %d",self.flipCount];
}
- (IBAction)flipCard:(UIButton *)sender
{
if (!sender.isSelected)
{
if (self.flipCount >= 52)
{
self.flipCount = 0;
self.myDeck = nil;
}
Card *cCard = [self.myDeck drawRandomCard];
[sender setTitle: [cCard contents] forState:UIControlStateSelected];
self.flipCount++;
}
sender.selected = !sender.isSelected;
}
@end
Upvotes: 0
Reputation: 2775
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 ::
- (IBAction)flipCard:(UIButton *)sender
{
//draw a random card
Card *randomCard = [self.cardDeck drawRandomCard];
//set the button title
[sender setTitle:[randomCard contents] forState:UIControlStateSelected];
if(sender.isSelected) {
sender.selected = NO;
self.flipCount ++;
}
else{
sender.selected = YES;
self.flipCount ++;
}
}
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.
Upvotes: 1