Hi
I've got this question about basics oop. Apparantly I have a problem grasping something about its keys. In attachment I'm adding two files. One file is the standard solution (oplossing Matchismo code in ps). The standard solution works, my alternative (mijn oplossing voor Machismo) does too. But I need some more explanation.
In the file called 'oplossing Matchismo' one finds the model (everything except for CardgameViewController) and the Controller (CardgameViewController). The controller provides the link between model and view. The View I didn't add (can do so if wanted). Here comes the questions:
In the CardgameViewController appears following line:
This causes my greatest problem. That card will be uses later on to summit the contents variable. The contents will have some value like 5Hearts. The class Card did have a contents variable. The method drawRandomCard of the class Deck returns indeed a pointer to an instance of the class Card. On initializing deck a pointer to a PlayCardDeck object is being given. In that PlayCardDeck object cards are being made and added of the class PlayingCard. Those cards do have a suit (hearts) and a rank (5).
HERE COMES THE PROBLEM. I'd like to write this:
I do not entirely grasp when the value of the contents of card is set upon 5 Hearts. I've tried to summon the instance variable suit of card (in the CardgameViewController). With reason an error is being thrown. Throwing an
This puzzles me for two reasons.
Firstly I wonder why the %@ returns a PlayingCard object while on the other hand I can't access the instance variable suits (withing CardgameViewController). I guess this is because the code puts the PlayingCardObject into a generic object of the class Card. An object of the class Card doesn't have this instance variable suit. But why does Xcode gives then 5Hearts as value of contents variable? On calling contents in CardgameViewController I'm calling the method of the class Card. This can't access suit and rank.
Unless the value of contents is set on creating the PlayingCard in PlayingCardDeck. Then again, that would imply that the value of each property is being set as I didn't type self.contents = ... in PlayingCardDeck. Even more, if Xcode would set a value it seems more reasonable this contents would be set on nil. The value of the property would be given on initialisation of PlayCard in PlayCardDeck I suppose so nil.
Hence I felt the need to type
. But I couldn't do so as deck's method drawRandomCard (PlayingCardDeck too as the method was not overriden) returns a pointer to an object of the class Card. If I had been able to use PlayingCard *card I would have understood how the value of card.contents was set upon 5Hearts.
I'm getting the impression that Xcode knows that the Card *card refers to a card of the class PlayingCard (despite the assignment to the generic super class Card). In that case card.contents would override the contents variable of the class Card by the contents variable of the subclass PlayingCard. Not clear then why I can't access the suit in that case.
I've added a second file (mijn oplossing voor Matchismo code in ps). It works too. I had made deck of the class PlayingCardDeck. The standard solution has an object of the class Deck and adds a pointer to an object of the subclass. Which seems to be the same problem. Anyway even in my solution I had to do Card *card instead of PlayingCard *card. (warning was thrown concerning pointers).
Thanks for your reading and answer !!!!
ps: standard solution code
ps: my solution .m controller
I've got this question about basics oop. Apparantly I have a problem grasping something about its keys. In attachment I'm adding two files. One file is the standard solution (oplossing Matchismo code in ps). The standard solution works, my alternative (mijn oplossing voor Machismo) does too. But I need some more explanation.
In the file called 'oplossing Matchismo' one finds the model (everything except for CardgameViewController) and the Controller (CardgameViewController). The controller provides the link between model and view. The View I didn't add (can do so if wanted). Here comes the questions:
In the CardgameViewController appears following line:
Code:
Card *card = [self.deck drawRandomCard];
HERE COMES THE PROBLEM. I'd like to write this:
Code:
PLAYINGCARD *card = [self.deck drawRandomCard];
Code:
nslog %@ at card (within CardgameViewController) returns <Playingcard and some numbers>
Firstly I wonder why the %@ returns a PlayingCard object while on the other hand I can't access the instance variable suits (withing CardgameViewController). I guess this is because the code puts the PlayingCardObject into a generic object of the class Card. An object of the class Card doesn't have this instance variable suit. But why does Xcode gives then 5Hearts as value of contents variable? On calling contents in CardgameViewController I'm calling the method of the class Card. This can't access suit and rank.
Unless the value of contents is set on creating the PlayingCard in PlayingCardDeck. Then again, that would imply that the value of each property is being set as I didn't type self.contents = ... in PlayingCardDeck. Even more, if Xcode would set a value it seems more reasonable this contents would be set on nil. The value of the property would be given on initialisation of PlayCard in PlayCardDeck I suppose so nil.
Hence I felt the need to type
Code:
PlayingCard *card = [self.deck drawRandomCard]
I'm getting the impression that Xcode knows that the Card *card refers to a card of the class PlayingCard (despite the assignment to the generic super class Card). In that case card.contents would override the contents variable of the class Card by the contents variable of the subclass PlayingCard. Not clear then why I can't access the suit in that case.
I've added a second file (mijn oplossing voor Matchismo code in ps). It works too. I had made deck of the class PlayingCardDeck. The standard solution has an object of the class Deck and adds a pointer to an object of the subclass. Which seems to be the same problem. Anyway even in my solution I had to do Card *card instead of PlayingCard *card. (warning was thrown concerning pointers).
Thanks for your reading and answer !!!!
ps: standard solution code
Code:
//
// Card.h
// Matchismo
//
// Created by m on 10/12/13.
// Copyright (c) 2013 m. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Card : NSObject
@property (strong, nonatomic) NSString *contents;
@property (nonatomic, getter = isChosen) BOOL chosen;
@property (nonatomic, getter = isMatched) BOOL matched;
- (int)match: (NSArray *)otherCards;
@end
//
// Card.m
// Matchismo
//
// Created by m on 10/12/13.
// Copyright (c) 2013 m. All rights reserved.
//
#import "Card.h"
@interface Card()
@end
@implementation Card
-(int)match:(NSArray *)otherCards
{
int score = 0;
for (Card *card in otherCards)
{
if ([card.contents isEqualToString:self.contents])
{
score = 1;
}
}
return score;
}
@end
//
// PlayingCard.h
// Matchismo
//
// Created by m on 10/12/13.
// Copyright (c) 2013 m. All rights reserved.
//
#import "Card.h"
@interface PlayingCard : Card
@property (strong, nonatomic) NSString *suit;
@property (nonatomic) NSUInteger rank;
+ (NSArray *)validSuits;
+ (NSUInteger)maxRank;
@end
//
// PlayingCard.m
// Matchismo
//
// Created by m on 10/12/13.
// Copyright (c) 2013 m. All rights reserved.
//
#import "PlayingCard.h"
@implementation PlayingCard
- (NSString *)contents
{
NSArray *rankStrings = [PlayingCard rankStrings];
return [rankStrings[self.rank] stringByAppendingString:self.suit];
}
@synthesize suit = _suit; //because we provide setter and getter
+(NSArray *)validSuits
{
return @[@"♠",@"♣",@"♥",@"♦"];
}
- (void)setSuit:(NSString *)suit
{
if ([[PlayingCard validSuits] containsObject: suit]) {
_suit = suit;
}
}
- (NSString *)suit
{
return _suit ? _suit : @"?";
}
+ (NSArray *)rankStrings
{
return @[@"?", @"A", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10", @"J", @"Q", @"K"];
}
+ (NSUInteger)maxRank
{
return [[self rankStrings]count]-1;
}
-(void)setRank:(NSUInteger)rank
{
if (rank <= [PlayingCard maxRank]) {
_rank = rank;
}
}
@end
//
// Deck.h
// Matchismo
//
// Created by m on 10/12/13.
// Copyright (c) 2013 m. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Card.h"
@interface Deck : NSObject
- (void)addCard: (Card *)card atTop: (BOOL)atTop;
- (void)addCard: (Card *)card;
- (Card *)drawRandomCard;
@end
//
// Deck.m
// Matchismo
//
// Created by m on 10/12/13.
// Copyright (c) 2013 m. All rights reserved.
//
#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 (atTop)
{
[self.cards insertObject:card atIndex:0];
}
else
{
[self.cards addObject:card];
}
}
- (void)addCard:(Card *)card
{
[self addCard:card atTop:NO];
}
-(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
//
// PlayingCardDeck.h
// Matchismo
//
// Created by m on 10/12/13.
// Copyright (c) 2013 m. All rights reserved.
//
#import "Deck.h"
@interface PlayingCardDeck : Deck
@end
//
// PlayingCardDeck.m
// Matchismo
//
// Created by m on 10/12/13.
// Copyright (c) 2013 m. All rights reserved.
//
#import "PlayingCardDeck.h"
#import "PlayingCard.h"
@implementation PlayingCardDeck
-(id)init
{
self = [super init];
if (self)
{
for (NSString *suit in [PlayingCard validSuits])
{
for (NSUInteger rank = 1; rank <= [PlayingCard maxRank] ; rank++) {
PlayingCard *card = [[PlayingCard alloc]init];
card.suit = suit;
card.rank = rank;
[self addCard:card];
}
}
}
return self;
}
@end
//
// CardgameViewController.h
// Matchismo
//
// Created by m on 10/12/13.
// Copyright (c) 2013 m. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface CardgameViewController : UIViewController
@end
//
// CardgameViewController.m
// Matchismo
//
// Created by m on 10/12/13.
// Copyright (c) 2013 m. All rights reserved.
//
#import "CardgameViewController.h"
#import "PlayingCardDeck.h"
@interface CardgameViewController ()
@property (weak, nonatomic) IBOutlet UILabel *flipsLabel;
@property (nonatomic) int flipCount;
@property (strong, nonatomic) Deck *deck;
@end
@implementation CardgameViewController
- (Deck *)deck
{
if (!_deck) _deck = [self createDeck];
return _deck;
}
- (Deck *)createDeck
{
return [[PlayingCardDeck alloc]init];
}
- (void) setFlipCount:(int)flipCount
{
_flipCount=flipCount;
self.flipsLabel.text=[NSString stringWithFormat:@"Flips: %d", self.flipCount];
}
- (IBAction)touchCardButton:(UIButton *)sender
{
if ([sender.currentTitle length])
{
[sender setBackgroundImage:[UIImage imageNamed:@"cardback"]
forState:UIControlStateNormal];
[sender setTitle:@"" forState:UIControlStateNormal];
self.flipCount++;
}
else
{
Card *card = [self.deck drawRandomCard];
NSLog(@"%@", card);
if(card)
{
[sender setBackgroundImage:[UIImage imageNamed:@"cardfront"]
forState:UIControlStateNormal];
[sender setTitle:card.contents forState:UIControlStateNormal];
self.flipCount++;
}
}
}
@end
ps: my solution .m controller
Code:
//
// CardgameViewController.m
// Matchismo
//
// Created by m on 10/12/13.
// Copyright (c) 2013 m. All rights reserved.
//
#import "CardgameViewController.h"
#import "PlayingCardDeck.h"
#import "PlayingCard.h"
@interface CardgameViewController ()
@property (weak, nonatomic) IBOutlet UILabel *flipsLabel;
@property (nonatomic) int flipCount;
@property (strong, nonatomic) PlayingCardDeck *kaardenDek;
@end
@implementation CardgameViewController
- (PlayingCardDeck *)kaardenDek
{
if (!_kaardenDek) _kaardenDek = [[PlayingCardDeck alloc]init];
return _kaardenDek;
}
- (void) setFlipCount:(int)flipCount
{
_flipCount=flipCount;
self.flipsLabel.text=[NSString stringWithFormat:@"Flips: %d", self.flipCount];
}
- (IBAction)touchCardButton:(UIButton *)sender
{
Card *kaart = [self.kaardenDek drawRandomCard];
if ([sender.currentTitle length]) {
[sender setBackgroundImage:[UIImage imageNamed:@"cardback"]
forState:UIControlStateNormal];
[sender setTitle:@"" forState:UIControlStateNormal];
} else {
[sender setBackgroundImage:[UIImage imageNamed:@"cardfront"]
forState:UIControlStateNormal];
[sender setTitle:kaart.contents forState:UIControlStateNormal];
}
self.flipCount++;
[self.kaardenDek addCard:kaart];
}
@end
Attachments
Last edited: