【问题标题】:How to use UISwitch to tell the controller to check a certain condition in a method如何使用 UISwitch 告诉控制器检查方法中的某个条件
【发布时间】:2013-03-14 17:45:55
【问题描述】:

在我的纸牌配对游戏中:

-我有一种方法可以检查在特定索引中翻转的卡片。它基本上是应用程序中的整个逻辑。

-我有另一种检查匹配的方法。

现在,我在视图控制器中创建了一个切换按钮,它将告诉控制器用户将模式更改为“3”卡而不是基本模式(2 卡)。

我的问题是,如果有超过 2 个匹配项,我如何告诉控制器检查匹配方法。这让我发疯,请帮我解决这个问题。

我在控制器中还有一个 updateUI 方法,可以让匹配的卡片消失,所以我需要确保它的行为相同。

以下代码展示了flipCardAtIndex方法,以相同的顺序匹配方法和视图控制器:

CardMatchingGame.m(最后一个方法是flipCardAtIndex):

#import "CardMatchingGame.h"
#import "PlayingCardsDeck.h"

@interface CardMatchingGame()

@property (readwrite, nonatomic) int score;
@property (strong, nonatomic) NSMutableArray *cards;
@property (strong, nonatomic) NSString *notification;
@end        


@implementation CardMatchingGame


-(NSMutableArray *) cards {

    if (!_cards) _cards = [[NSMutableArray alloc] init];
    return _cards;
}


-(id)initWithCardCount:(NSUInteger)count usingDeck:(Deck *)deck {

    self = [super init];

    if (self) {

        for (int i = 0; i < count; i++) {
            Card *card = [deck drawRandonCard];

            if (!card) {
                self = nil;
            } else {
                self.cards[i] = card;
            }
        }
    }
    return self;
}

-(Card *) cardAtIndex:(NSUInteger)index {

    return (index < self.cards.count) ? self.cards[index] : nil;
}

#define FLIP_COST 1
#define MISMATCH_PENALTY 2
#define BONUS 4

-(void) flipCardAtIndex:(NSUInteger)index {



    Card *card = [self cardAtIndex:index];

    if (!card.isUnplayable) {

        if (!card.isFaceUp) {

            for (Card *otherCard in self.cards) {

                if (otherCard.isFaceUp && !otherCard.isUnplayable) {

                    NSMutableArray *myCards = [[NSMutableArray alloc] init];

                    [myCards addObject:otherCard];

                    int matchScore = [card match:myCards];

                    if (matchScore) {

                        otherCard.unplayble = YES;
                        card.unplayble = YES;

                        self.notification = [NSString stringWithFormat:@"%@ & %@  match!", card.contents, otherCard.contents];

                        self.score += matchScore * BONUS;
                    } else {
                        otherCard.faceUp = NO;
                        self.score -= MISMATCH_PENALTY;
                        self.notification = [NSString stringWithFormat:@"%@ did not matched to %@", card.contents, otherCard.contents];
                    }
                    break;
                }

            }
            self.score -= FLIP_COST;
        }
        card.faceUp = !card.isFaceUp;   
    }
}
@end

PlayingCards.m(仅第一种方法,匹配方法):

#import "PlayingCards.h"


@implementation PlayingCards

@synthesize suit = _suit;

//overriding the :match method of cards to give different acore if its only a suit match or a number match
-(int)match:(NSArray *)cardToMatch {

    int score = 0;

    for (int i = 0; i < cardToMatch.count; i++) {

        PlayingCards *nextCard = cardToMatch[i];
        if ([nextCard.suit isEqualToString:self.suit]) {

            score += 1;
        } else if (nextCard.rank == self.rank) {

            score += 4;
        }
    }

   return score;

}

我的视图控制器(最后一种方法是切换按钮):

#import "CardGameViewController.h"
#import "PlayingCardsDeck.h"
#import "CardMatchingGame.h"


@interface CardGameViewController ()

@property (weak, nonatomic) IBOutlet UILabel *flipsLabel;
@property (weak, nonatomic) IBOutlet UILabel *notificationLabel;
@property (weak, nonatomic) IBOutlet UILabel *scoreCounter;
@property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *cardButtons;
@property (strong, nonatomic) CardMatchingGame *game;
@property (nonatomic) int flipsCount;

@property (nonatomic) NSNumber *mode;
//@property (weak, nonatomic) IBOutlet UISwitch *mySwitch;
@property (weak, nonatomic) IBOutlet UISwitch *mySwitch;

@end


@implementation CardGameViewController

@synthesize mode = _mode;

//creating the getter method that creates a new card game.
-(CardMatchingGame *) game {

    if (!_game) _game = [[CardMatchingGame alloc] initWithCardCount:self.cardButtons.count usingDeck:[[PlayingCardsDeck alloc] init]];
    return _game;
}

//creating a setter for the IBOutletCollection cardButtons
-(void) setCardButtons:(NSArray *)cardButtons {

    _cardButtons = cardButtons;
   [self updateUI];
}


//creating the setter for the flipCount property. Whick is setting the flipsLabel to the right text and adding the number of counts.
-(void) setFlipsCount:(int)flipsCount {

    _flipsCount = flipsCount;
    self.flipsLabel.text = [NSString stringWithFormat:@"Flips: %d", self.flipsCount];

}


-(void) updateUI {

    for (UIButton *cardButton in self.cardButtons) {
        Card *card = [self.game cardAtIndex:[self.cardButtons indexOfObject:cardButton]];
        [cardButton setTitle:card.contents forState:UIControlStateSelected];
        [cardButton setTitle:card.contents forState:UIControlStateSelected|UIControlStateDisabled];
        cardButton.selected = card.isFaceUp;
        cardButton.enabled = !card.unplayble;
        if (card.unplayble) {
            cardButton.alpha = 0.1;
        }

        //updating the score 
        self.scoreCounter.text = [NSString stringWithFormat:@"Score: %d", self.game.score];

        //if notification in CardMatchingGame.m is no nil, it will be presented 
        if (self.game.notification) {

        self.notificationLabel.text = self.game.notification;

        }
    }
}

//Here I created a method to flipCards when the card is selected, and give the user a random card from the deck each time he flips the card. After each flip i'm incrementing the flipCount setter by one.
- (IBAction)flipCard:(UIButton *)sender {

    [self.game flipCardAtIndex:[self.cardButtons indexOfObject:sender] forMode:self.mode];
    self.flipsCount++;
    [self updateUI];
}

//sending an alert if the user clicked on new game button
- (IBAction)newGame:(UIButton *)sender {

   UIAlertView* mes=[[UIAlertView alloc] initWithTitle:@"Are you sure..?" message:@"This will start a new game" delegate:self cancelButtonTitle:@"No" otherButtonTitles:@"Yes", nil];

    [mes show];

}

//preforming an action according to the user choice for the alert yes/no to start a new game
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {

    if (buttonIndex != [alertView cancelButtonIndex]) {

        self.flipsCount = 0;
        self.game = nil;
        for (UIButton *button in self.cardButtons) {
            Card *card = [self.game cardAtIndex:[self.cardButtons indexOfObject:button]];
            card.unplayble = NO;
            card.faceUp = NO;
            button.alpha = 1;
        }

        self.notificationLabel.text = nil;
        [self updateUI];

    }
}

-(void) setMode:(NSNumber *)mode {

    mode = _mode;
}

-(void) switchValueChange:(id)sender {

    UISwitch *Switch = (UISwitch *) sender;

    NSNumber *twoCards = [NSNumber numberWithInt:2];
    NSNumber *threeCards = [NSNumber numberWithInt:3];


    if (Switch.on) {
        self.mode = twoCards;
    }
    else
    {
        self.mode = threeCards;
    }
}


- (void)viewDidLoad
{
    UISwitch *mySwitch;
    [super viewDidLoad];
    [mySwitch addTarget:self action:@selector(switchValueChange:) forControlEvents:UIControlEventValueChanged];
    [self updateUI];

}

@end

【问题讨论】:

  • 我不完全清楚你在这里问什么。您只是在编写一个同时比较三张卡片的方法时遇到问题吗?
  • 嘿 Max,不,我想看看模型如何识别他需要测试 3 张卡而不是一张卡,并将其传递给控制器​​。 (当然,开关应该告诉控制器他需要从模型中询问这个计算,这对 mvc 来说非常新,所以我希望我做对了)。计算匹配的方法已经在做这项工作。问题是这个方法如何处理控制器匹配 3 而不是 2 @Max

标签: iphone ios objective-c cocoa-touch cocoa


【解决方案1】:

实际上,获取开关值是很容易的部分。你可以设置一个从你的 switch 到你的 viewController (CardGameViewController) 的引用出口,并在你的 view controller 的 viewDidLoad 方法中,添加监听 switch 值变化的方法:

[mySwitch addTarget:self action:@selector(switchValueChange:) forControlEvents:UIControlEventValueChanged];

在您的 CardGameViewController 中添加一个名为 NSNumber *mode 的新属性并合成它。 现在您可以在 switchValueChanged 方法中更新“模式”(我相信它可能是一个实例变量):

- (void)switchValueChange:(id)sender
  {
      UISwitch *switch = (UISwitch *) sender;
      if (sender.on)
        self.mode = 2;
      else
        self.mode = 3;
  }

如果我的假设是正确的,那么“模式”是指要匹配多少张卡片,对吗? 2 表示至少 2 张牌正面朝上时应相同,3 表示 3 张牌应在花色或数字上匹配。

首先将您的 PlayingCards 中的 match 方法更改为类似的内容(接受另一个名为 mode 的参数)(您可能也必须在其父类中更新相同的方法):

//overriding the :match method of cards to give different acore if its only a suit match or a number match
-(int)match:(NSArray *)cardToMatch forMode:(NSNumber *) mode{

    int score = 0;
    int cardsMatched = 0;

    for (int i = 0; i < cardToMatch.count; i++) {

        PlayingCards *nextCard = cardToMatch[i];
        if ([nextCard.suit isEqualToString:self.suit]) {

            score += 1;
            cardsMatched++;
        } else if (nextCard.rank == self.rank) {

            score += 4;
            cardsMatched++;
        }

        if (cardsMatched >= [mode intValue])
          break;

    }

   return score;

}

现在,在您的 CardMatchingGame.m 方法中,将 flipCardAtIndex 方法更改为此(接受另一个名为 mode 的参数):

-(void) flipCardAtIndex:(NSUInteger)index forMode (NSNumber *mode) {

    Card *card = [self cardAtIndex:index];

    if (!card.isUnplayable) {

        if (!card.isFaceUp) {

            NSMutableArray *myFaceUpCards = [[NSMutableArray alloc] init];



            // UPDATED: Loop through all the cards that are faced up and add them to an array first
            for (Card *otherCard in self.cards) {

                if (otherCard.isFaceUp && !otherCard.isUnplayable && orderCard != card) {

                    [myCards addObject:otherCard];
             }

             // UPDATED: Now call the method to do the match. The match method now takes an extra parameter
                    int matchScore = [card match:myCards forMode:mode];



                    if (matchScore) {

                        otherCard.unplayble = YES;
                        card.unplayble = YES;

                        self.notification = [NSString stringWithFormat:@"%@ & %@  match!", card.contents, otherCard.contents];

                        self.score += matchScore * BONUS;
                    } else {
                        otherCard.faceUp = NO;
                        self.score -= MISMATCH_PENALTY;
                        self.notification = [NSString stringWithFormat:@"%@ did not matched to %@", card.contents, otherCard.contents];
                    }

            }
            self.score -= FLIP_COST;
        }
        card.faceUp = !card.isFaceUp;   
    }
}

最后,将调用改为

[self.game flipCardAtIndex:[self.cardButtons indexOfObject:sender]];

在

- (IBAction)flipCard:(UIButton *)sender 

CardGameViewController 的方法

[self.game flipCardAtIndex:[self.cardButtons indexOfObject:sender] forMode:self.mode];

看看这是否有意义。

【讨论】:

  • 我应该在哪里声明mode 属性?
  • 无论哪个 viewController 都嵌入了 UISwitch。我在这里假设它是 CardMatchingGame。
  • CardMatchingGame 是模型,带有开关的控制器是 CardGameViewController(我分享的最后一个类)。我想我解决了我在尝试使用新匹配时遇到的问题:方法我得到了一个错误,我缺少一个属性mode,所以我在 CardMatchingGame 中添加了一个property (nonatomic) int mode(其中flipCards 逻辑在)。可以吗?
  • 我无法测试它,因为我现在正试图找出控制器:?
  • PlayingCards 类具有 match: 方法,CardMatchingGame 具有翻转卡片的逻辑(它们都是模型的一部分),CardGameViewController 是我的控制器。我真的很坚持,这让我发疯@AC1
【解决方案2】:

从您的 .m 类中删除 @property (weak, nonatomic) IBOutlet UISwitch *mySwitch;。 相反,转到您的故事板,单击具有开关的控制器,然后单击右上角的助手编辑器按钮(看起来像一张脸)。它将打开 CardGameViewController.h。现在右键单击故事板上的切换视图,然后单击并从 New Referencing Outlet 拖动到 CardViewController.h。这就是您将开关引用到控制器中的方式。 现在你已经在接口文件中有了 switch 变量,进入你的实现文件 (CardGameViewController.m) 并合成变量:

@synthesize mySwitch = _mySwitch;

现在,将您的 viewDidLoad 方法更改为:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.mySwitch addTarget:self action:@selector(switchValueChange:) forControlEvents:UIControlEventValueChanged];
    [self updateUI];

}

同时删除 setMode 方法。如果您正在合成模式变量,则不需要它。

现在试一试。你知道如何在 xcode 中使用断点进行调试吗?

【讨论】:

    猜你喜欢
    • 2018-06-14
    • 2012-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多