麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

(6/18)重學Standford_iOS7開發_控制器多態性、導航控制器、選項卡欄控制器_課程筆記

2019-11-14 18:49:45
字體:
來源:轉載
供稿:網友

  終于有時間跟新了,兩周時間復(yu)習(xi)了5門考試累覺不愛。。。。。。

--------------------------------------------------------------------------我是正文分割線---------------------------------------------------------------------------------------------

第六課

  1、控制器多態性

    這里控制器多態性是指在控制器中使用繼承,通過繼承構造通用視圖控制器(ViewController),在具體的MVC中繼承通用視圖控制器實現具體功能(通常是父類中的抽象方法)

    注意:objective-C并沒有abstract關鍵字,因此通常要通過注釋的方式說明,抽象方法需要在.h文件中聲明,一般實現文件中的抽象方法沒有具體功能,只返回nil。

    storyboard的多態控制器類需要在屬性檢查器中更改指定的類。

    說明:通過繼承,父類中的連接也會被完整的繼承下來,如輸出口(Outlet)等。

    demo地址:https://github.com/NSLogMeng/Stanford_iOS7_Study/commit/238167d6080df94e0383aceccab6d16fea290af2

  2、多MVC

    理解:多MVC基本組合方式,子MVC作為父MVC的視圖(View)呈現。

      

    (1)UINavigationController(以日歷應用為例)

      1) Navigation Bar 

        a.title 當前MVC的標題,與內容有關

        b.navigationItem.rightBarButtonItems(ViewController屬性)  功能按鈕(注意與UIButton區別,UIBarButton的數組,即可以嵌入多個BarButton)

        c.Back Button (一般由UINavigationController自動設定,默認為上一MVC的title,長度較長時顯示為back,亦可自行設置) 

          當點擊當前MVC的back時,當前MVC會被釋放,返回前一個MVC

      2)toolbarItems (ViewController屬性)

        底部出現(an NSArray of UIBarButtonItems )

      3)rootViewController

        指向一個MVC的controller,作為根MVC

//UINavigationController常用方法- (instancetype)initWithRootViewController:(UIViewController *)rootViewController; // 設置根視圖控制器- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated; //壓入新視圖- (UIViewController *)popViewControllerAnimated:(BOOL)animated;//彈出當前視圖//navigationBar@PRoperty(nonatomic,getter=isNavigationBarHidden) BOOL navigationBarHidden;- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated;//toolbar@property(nonatomic,getter=isToolbarHidden) BOOL toolbarHidden NS_AVAILABLE_IOS(3_0);- (void)setToolbarHidden:(BOOL)hidden animated:(BOOL)animated NS_AVAILABLE_IOS(3_0);

 

    (2)segue(非常重要,MVC間切換的基礎)

        push:一種以push,pop方式在UINavigationController上進行MVC切換的方式   

        identifier:用來表示push,方便在代碼中使用

 1 //需要跳轉時的Action 2 - (IBAction)rentEquipment 3 { 4     if (self.snowTraversingTalent == Skiing) { 5         [self performSegueWithIdentifier:@“AskAboutSkis” sender:self]; 6     } else { 7         [self performSegueWithIdentifier:@“AskAboutSnowboard” sender:self]; 8     }  9 }10 11 //為各segue做跳轉前的準備12 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {13     if ([segue.identifier isEqualToString:@“DoSomething”]) {14         if ([segue.destinationViewController isKindOfClass:[DoSomethingVC class]])         {15             DoSomethingVC *doVC = (DoSomethingVC *)segue.destinationViewController;16 doVC.neededInfo = ...; }17 } 18 }19 20 //segue跳轉判斷21 - (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {22 ?    if ([segue.identifier isEqualToString:@“DoAParticularThing”]) {23         return [self canDoAParticularThing] ? YES : NO;24     }25 }

        注意:segue跳轉的準備工作中并未設置好輸出口,因此不能直接賦值給新MVC的輸出口,MVC中需要設置API來接收數據。 

    (3)demo : Attributor Stats

       Use a UINavigationController to show “statistics” on colors and outlining in Attributor. 

      demo地址:https://github.com/NSLogMeng/Stanford_iOS7_Study/commit/fba52faaefd72cb1d4e0ef0c9029092fd5749f63

    (4)UITabBarController(以時鐘應用為例)

//設置選項個數,一般不超過5個,超過5個時,第五個及其他將集合在最后一欄@property (nonatomic, strong) NSArray *viewControllers;

  3、作業

    要求:a.在Matchismo 的基礎上添加一個新的MVC作為Set紙牌匹配游戲

       b.新的Set紙牌游戲與原紙牌游戲類似(3張牌匹配模式)

       c.原游戲的功能保留,可以適當刪減或更改UI(原要求是取消UISegmentedControll) 

       d.使用UITabBarController將兩個游戲分開

       e.Set紙牌的數目可能會與之前不同,選擇合適的UI尺寸

       f.使用▲ ● ■  以及NSAttributedString 來表示Set紙牌的三個屬性(形狀,顏色,陰影)

       g.每個游戲必須展示當前的得分狀況,并允許用戶重置

       h.使用NSAttributedString來記錄并展示紙牌匹配狀況

       i.使用UINavigationController 添加新的MVC來詳細展示紙牌匹配情況的歷史

       Set紙牌游戲規則:Wikipedia 或 百度百科

  作業解析:

      最終實現效果如下圖:

        

      實現過程:

         針對上次作業的結果對紙牌游戲再次進行抽象化并添加Set紙牌游戲

抽象化結果:https://github.com/NSLogMeng/Stanford_iOS7_Study/commit/58afa7577cb339328819fccb5422aef27fd843ff

a.添加Set及Model的抽象化

SetCard

  SetCard的匹配詳見作業要求中的規則,此處判定匹配成功則score為1,否則為0(僅作為判定標記,也可以根據自己喜好自定義分數規則)

 1 #import "Card.h" 2   3 @interface SetCard : Card 4   5 @property (strong,nonatomic) NSString *suit;//  ▲ ● ■ 6 @property (strong,nonatomic) NSString *color;// red green purple 7 @property (nonatomic) BOOL shading; 8  9 + (NSArray *)validSuits;10 + (NSArray *)validColors;11 + (NSUInteger)shadingNumber;12 13 @end
 1 #import "SetCard.h" 2  3 @interface SetCard() 4  5 @end 6  7 @implementation SetCard 8  9 - (NSString *)contents10 {11     return nil;12 }13 14 - (int)match:(NSArray *)otherCards15 {16     int score = 0;17    18     if ([otherCards count] == 2)19     {20         SetCard *firstCard = [otherCards firstObject];21         SetCard *secondCard = [otherCards lastObject];22         if ([self.suit isEqualToString:firstCard.suit] && [firstCard.suit isEqualToString:secondCard.suit])23         {24             score += 1;25         }26         else if (![self.suit isEqualToString:firstCard.suit] && ![self.suit isEqualToString:secondCard.suit] && ![firstCard.suit isEqualToString:secondCard.suit])27         {28             score += 1;29         }30         else31         {32             score -= 1;33         }34         35         if ([self.color isEqualToString:firstCard.color] && [firstCard.color isEqualToString:secondCard.color])//全相等36         {37             score += 1;38         }39         else if (![self.color isEqualToString:firstCard.color] && ![self.color isEqualToString:secondCard.color] && ![firstCard.color isEqualToString:secondCard.color])//全不相等40         {41             score += 1;42         }43         else44         {45             score -= 1;46         }47         48         if ((self.shading == firstCard.shading) && (firstCard.shading == secondCard.shading))49         {50             score += 1;51         }52         else53         {54             score -= 1;55         }56 57     }58     59     if (score == 3)60     {61         score = 1;62     }63     else64     {65         score = 0;66     }67     68     return score;69 }70 71 + (NSArray *)validSuits72 {73     return @[@"",@"▲▲",@"▲▲▲",@"",@"●●",@"●●●",@"",@"■ ■",@"■ ■ ■"];74 }75 76 + (NSArray *)validColors77 {78     return @[@"red",@"green",@"purple"];79 }80 81 82 + (NSUInteger)shadingNumber83 {84     return 2;85

SetCardDeck

  與PlayingCardDeck類似

1 #import "Deck.h"2 3 @interface SetCardDeck : Deck4 5 @end
 1 #import "SetCardDeck.h" 2 #import "SetCard.h" 3  4 @implementation SetCardDeck 5  6 - (instancetype) init 7 { 8     self = [super init]; 9     if (self)10     {11         for (NSString *suit in [SetCard validSuits])12         {13             for (NSString *color in [SetCard validColors])14             {15                     for (NSUInteger i = 0; i < [SetCard shadingNumber]; i++)16                     {17                         SetCard *card = [[SetCard alloc] init];18                         card.suit = suit;19                         card.color = color;20                         card.shading = (i<1) ? true : false;21                         22                         [self addCard:card];23                     }24             }25         }26     }27     return self;28 }29 30 @end

CardMatchingGame的抽象化

  上次作業中我們的CardMatchingGame只針對PlayingCard的匹配規則及方法在SetCard中任然類似或適用,因此我們抽象化CardMatchingGame,使其成為PlayingCardMatchingGame與SetCardMatchingGame的超類。

首先我們根據作業要求我們添加gameStateHistory屬性來保存游戲進行的歷史數據,由于可能會出現多紙牌匹配,因此添加validOfOtherCards屬性來獲取其余紙牌的內容。因為gameState屬性最好使用只讀屬性,因此我們在超類中去除此屬性而在子類中實現

 1 #import <Foundation/Foundation.h> 2 #import "Deck.h" 3 #import "Card.h" 4  5 static const int MISMATCH_PENALTY = 2; 6 static const int MATCH_BOUNDS = 4; 7 static const int COST_TO_CHOOSE = 1; 8  9 @interface CardMatchingGame : NSObject10 11 // designated initializer12 - (instancetype) initWithCardCount:(NSUInteger)count13                          usingDeck:(Deck *)deck;14 - (void) chooseCardAtIndex:(NSUInteger)index;15 - (Card *) cardAtIndex:(NSUInteger)index;16 17 - (NSString *)validOfOtherCards:(NSArray *)otherCards;18 19 @property (nonatomic,readonly) NSString *validOfOtherCards;20 @property (nonatomic,readonly) NSInteger score;21 @property (nonatomic) NSUInteger gameModel;// >=222 @property (nonatomic,strong) NSMutableArray *gameStateHistory;23 24 @end
  1 #import "CardMatchingGame.h"  2   3 @interface CardMatchingGame()  4   5 @property (nonatomic,readwrite) NSString *validOfOtherCards;  6 @property (nonatomic,readwrite) NSInteger score;  7 @property (nonatomic,strong) NSMutableArray *cards;//of playingcard  8   9 @end 10  11 @implementation CardMatchingGame 12  13 - (NSMutableArray *)cards 14 { 15     if (!_cards) _cards = [[NSMutableArray alloc] init]; 16     return _cards; 17 } 18  19 - (NSMutableArray *)gameStateHistory 20 { 21     if (!_gameStateHistory) 22     { 23         _gameStateHistory = [[NSMutableArray alloc] init]; 24     } 25     return _gameStateHistory; 26 } 27  28 - (instancetype) initWithCardCount:(NSUInteger)count usingDeck:(Deck *)deck 29 { 30     self = [super init]; 31     if (self) 32     { 33         for (int i = 0; i < count; i++) 34         { 35             Card *card = [deck drawRandomCard]; 36             if (card) 37             { 38                 [self.cards addObject:card]; 39             } 40             else 41             { 42                 self = nil; 43                 break; 44             } 45         } 46     } 47      48     return self; 49 } 50  51 - (Card *) cardAtIndex:(NSUInteger)index 52 { 53     return (index < [self.cards count]) ? self.cards[index] : nil; 54 } 55  56 - (void) chooseCardAtIndex:(NSUInteger)index 57 { 58     Card *card = [self cardAtIndex:index]; 59     if (!card.isMacthed) 60     { 61         if (card.isChosen) 62         { 63             card.chosen = NO; 64         } 65         else 66         { 67             // match against other chosen cards 68             NSMutableArray *otherCards = [NSMutableArray arrayWithCapacity:self.gameModel]; 69              70             for (Card *otherCard in self.cards) 71             { 72                 if (otherCard.isChosen && !otherCard.isMacthed) 73                 { 74                     [otherCards addObject:otherCard]; 75                 } 76             } 77              78             //不能放于for循環之前,否則會將本次被選擇的牌加入cards,不能放于下面的if之后,否則當if成立時返回,沒有將本次翻牌的cost記錄,且不能翻牌 79             self.score -= COST_TO_CHOOSE * self.gameModel; 80             card.chosen = YES; 81              82             if ([otherCards count] < self.gameModel - 1) 83             { 84                 return; 85             } 86             else 87             { 88                 self.validOfOtherCards = [self validOfOtherCards:otherCards]; 89                 int matchScore = [card match:otherCards]; 90                  91                 if (matchScore) 92                 { 93                     self.score += matchScore * MATCH_BOUNDS * self.gameModel; 94                     for (Card *otherCard in otherCards) 95                     { 96                         otherCard.matched = YES; 97                     } 98                     card.matched = YES; 99                 }100                 else101                 {102                     self.score -= MISMATCH_PENALTY * self.gameModel;103                     for (Card *otherCard in otherCards)104                     {105                         otherCard.chosen = NO;106                     }107                 }108             }109         }110     }111 }112 113 - (NSString *)validOfOtherCards:(NSArray *)otherCards114 {115     NSMutableString *string = [[NSMutableString alloc] init];116     for (Card *card in otherCards)117     {118         [string appendFormat:@"%@ ",card.contents];119     }120     return string;121 }122 123 @end

 

子類化的PlayingCardMatchingGame

  實現類gameState的記錄,并添加方法使其在紙牌匹配時記錄狀態及狀態歷史

1 #import "CardMatchingGame.h"2 3 @interface PlayingCardMatchingGame : CardMatchingGame4 5 @property (nonatomic,readonly) NSString *gameState;6 7 @end
 1 #import "PlayingCardMatchingGame.h" 2  3 @interface PlayingCardMatchingGame() 4  5 @property (nonatomic,readwrite) NSString *gameState; 6  7 @end 8  9 @implementation PlayingCardMatchingGame10 11 - (void)chooseCardAtIndex:(NSUInteger)index12 {13     int forwardScore = self.score;14     [super chooseCardAtIndex:index];15     [self updateGameState:forwardScore withIndexOfCard:index];16 }17 18 - (void)updateGameState:(int)forwardScore withIndexOfCard:(int)index19 {20     if (self.score == forwardScore - self.gameModel * COST_TO_CHOOSE)21     {22         _gameState = [self cardAtIndex:index].contents;23     }24     else if (self.score < (forwardScore - self.gameModel * COST_TO_CHOOSE))25     {26         _gameState = [NSString stringWithFormat:@"%@ with %@ not matched. %d point penalty!",[self cardAtIndex:index].contents,self.validOfOtherCards,forwardScore - self.score];27         [self.gameStateHistory addObject:_gameState];28     }29     else if (self.score > (forwardScore - self.gameModel * COST_TO_CHOOSE))30     {31         _gameState = [NSString stringWithFormat:@"%@ matched %@ . get %d score!",[self cardAtIndex:index].contents,self.validOfOtherCards,self.score - forwardScore];32         [self.gameStateHistory addObject:_gameState];33     }34 }35 36 @end

 

子類化的SetCardMatchingGame

  與PlayingCardMatchingGame類似,注意在SetCard中并沒有content的數據,因此要重寫validOfOtherCard:方法,以保證正確獲取SetCard的內容

1 #import "CardMatchingGame.h"2 3 @interface SetCardMatchingGame : CardMatchingGame4 5 @property (nonatomic,readonly) NSString *gameState;6 7 @end
 1 #import "SetCardMatchingGame.h" 2 #import "SetCard.h" 3  4 @interface SetCardMatchingGame() 5  6 @property (nonatomic,readwrite) NSString *gameState; 7  8 @end 9 10 @implementation SetCardMatchingGame11 12 - (void)chooseCardAtIndex:(NSUInteger)index13 {14     int forwardScore = self.score;15     [super chooseCardAtIndex:index];16     [self updateGameState:forwardScore withIndexOfCard:index];17 }18 19 - (NSString *)validOfOtherCards:(NSArray *)otherCards20 {21     NSMutableString *string = [[NSMutableString alloc] init];22     for (SetCard *card in otherCards)23     {24         [string appendString:card.suit];25     }26     return string;27 }28 29 - (void)updateGameState:(int)forwardScore withIndexOfCard:(int)index30 {31     if (self.score == forwardScore - (self.gameModel * COST_TO_CHOOSE))32     {33         _gameState = ((SetCard *)[self cardAtIndex:index]).suit;34     }35     else if (self.score < (forwardScore - (self.gameModel * COST_TO_CHOOSE)))36     {37         _gameState = [NSString stringWithFormat:@"%@ with %@ not matched. %d point penalty!",((SetCard *)[self cardAtIndex:index]).suit,self.validOfOtherCards,forwardScore - self.score];38         [self.gameStateHistory addObject:_gameState];39     }40     else if (self.score > (forwardScore - (self.gameModel * COST_TO_CHOOSE)))41     {42         _gameState = [NSString stringWithFormat:@"%@ matched %@ . get %d score!",((SetCard *)[self cardAtIndex:index]).suit,self.validOfOtherCards,self.score - forwardScore];43         [self.gameStateHistory addObject:_gameState];44     }45 }46 47 @end

 b.UI的更新

  如圖:

  由于SetCard的游戲規則,SetCard并不會被翻回到背面,因此要更改紙牌的牌面圖片

c.Controller的抽象化及子類化實現

  上次作業中針對ViewController有很多只與PlayingCardMatchingGame有關的內容,此次將這些內容轉移到PlayingCardGameViewController中,對ViewController進行抽象化,并且也在子類SetCardGameViewController中實現SetCard匹配游戲

ViewController

  由于許多有關UI的操作需要在子類中實現,因此將他們放到.h文件中,同時titleForCard:與backgroundImageForCard:方法也許要在SetCard子類中重寫(想想為什么?),因此也放入.h文件中

 1 #import <UIKit/UIKit.h> 2 #import "Deck.h" 3  4 @class CardMatchingGame; 5  6 @interface ViewController : UIViewController 7  8 //protected 9 //for subclasses10 - (Deck *)createDeck;  // abstract11 12 @property (strong,nonatomic) CardMatchingGame *game;13 @property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *cardButtons;14 @property (weak, nonatomic) IBOutlet UILabel *scoreLable;15 16 - (NSUInteger)cardButtonsNumber;17 - (void) updateUI;18 - (NSString *)titleForCard:(Card *)card;19 - (UIImage *)backgroundImageForCard:(Card *)card;20 21 @end
 1 #import "ViewController.h" 2 #import "CardMatchingGame.h" 3  4 @interface ViewController () 5  6 @end 7  8 @implementation ViewController 9 10 - (NSUInteger)cardButtonsNumber11 {12     return [_cardButtons count];13 }14 15 - (Deck *)createDeck  // abstract16 {17     return nil;18 }19 20 - (IBAction)touchCardButton:(UIButton *)sender21 {22     NSUInteger cardIndex = [self.cardButtons indexOfObject:sender];23     [self.game chooseCardAtIndex:cardIndex];24     [self updateUI];25 }26 27 - (void) updateUI28 {29     for (UIButton *cardButton in self.cardButtons)30     {31         NSUInteger cardIndex = [self.cardButtons indexOfObject:cardButton];32         Card *card = [self.game cardAtIndex:cardIndex];33         [cardButton setTitle:[self titleForCard:card] forState:UIControlStateNormal];34         [cardButton setBackgroundImage:[self backgroundImageForCard:card] forState:UIControlStateNormal];35         cardButton.enabled = !card.isMacthed;36     }37     self.scoreLable.text = [NSString stringWithFormat:@"Score:%ld",(long)self.game.score];38 }39 40 - (NSString *)titleForCard:(Card *)card41 {42     return card.isChosen ? card.contents : nil;43 }44 45 - (UIImage *)backgroundImageForCard:(Card *)card46 {47     return [UIImage imageNamed:card.isChosen ? @"cardFront" : @"cardBack"];48 }49 50 @end

PlayingCardGameController

  與上次作業基本相同,只不過變為從更抽象的超類中繼承為子類(一些只適用于PlayingCardGame的UI與方法在本類實現),并且添加了History功能

1 #import "ViewController.h"2 3 @interface PlayingCardGameViewController : ViewController4 5 @end
  1 #import "PlayingCardGameViewController.h"  2 #import "PlayingCardDeck.h"  3 #import "PlayingCardMatchingGame.h"  4 #import "HistoryViewController.h"  5   6 @interface PlayingCardGameViewController ()  7   8 @property (weak, nonatomic) IBOutlet UISegmentedControl *gameModelSelectSegmented;  9 @property (weak, nonatomic) IBOutlet UILabel *gameModelLable; 10 @property (weak, nonatomic) IBOutlet UITextField *matchModelTextFiled; 11 @property (weak, nonatomic) IBOutlet UILabel *gameStateLable; 12 @property (weak, nonatomic) IBOutlet UIButton *restartButton; 13 @property (nonatomic) NSUInteger selfDefiningModel; 14  15 @end 16  17 @implementation PlayingCardGameViewController 18  19 #define CORNER_FONT_STANDARD_HIGHT 180.0 20 #define CORNER_RADIUS 12.0 21  22 //讓界面變得更好看的魔法 23 - (CGFloat)cornerScaleFactor:(CGFloat)height {return height / CORNER_FONT_STANDARD_HIGHT;} 24 - (CGFloat)cornerRadius:(CGFloat)height {return CORNER_RADIUS * [self cornerScaleFactor:height];} 25  26 - (void)viewDidLoad 27 { 28     //又是個讓界面變得更好看的魔法 29     self.restartButton.layer.cornerRadius = [self cornerRadius:self.restartButton.bounds.size.height]; 30     self.gameModelSelectSegmented.layer.cornerRadius = [self cornerRadius:self.gameModelSelectSegmented.bounds.size.height * 3]; 31      32     [self.gameModelSelectSegmented addTarget:self action:@selector(segmentAction:) forControlEvents:UIControlEventValueChanged];//target-action 33      34     _selfDefiningModel = 2;//default model 35 } 36  37 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 38 { 39     if ([segue.identifier isEqualToString:@"show PlayingCardGameHistory"]) 40     { 41         if ([segue.destinationViewController isKindOfClass:[HistoryViewController class]]) 42         { 43             HistoryViewController *HVC = (HistoryViewController *)segue.destinationViewController; 44             HVC.history = self.game.gameStateHistory; 45         } 46     } 47 } 48  49  50 - (void) segmentAction:(UISegmentedControl *)Seg 51 { 52     if  (self.gameModelSelectSegmented.selectedSegmentIndex == 2) 53     { 54         [self assertSelfDefiningModel:self.matchModelTextFiled.text]; 55     } 56     else 57     { 58         self.selfDefiningModel = self.gameModelSelectSegmented.selectedSegmentIndex + 2; 59     } 60     self.gameModelLable.text = [NSString stringWithFormat:@"game model:%lu",(unsigned long)self.selfDefiningModel]; 61 } 62  63 - (void) assertSelfDefiningModel:(NSString *)text 64 { 65     if ([self.matchModelTextFiled.text integerValue] < 2) 66     { 67         [[[UIAlertView alloc] initWithTitle:@"Wrong" message:@"game model at least 2" delegate:nil cancelButtonTitle:@"certain" otherButtonTitles:nil, nil] show]; 68         self.matchModelTextFiled.text = @""; 69         self.gameModelSelectSegmented.selectedSegmentIndex = 0; 70     } 71     else if ([self.matchModelTextFiled.text integerValue] > [self cardButtonsNumber]) 72     { 73         [[[UIAlertView alloc] initWithTitle:@"Wrong" message:@"beyond card max number" delegate:nil cancelButtonTitle:@"certain" otherButtonTitles:nil, nil] show]; 74         self.matchModelTextFiled.text = @""; 75         self.gameModelSelectSegmented.selectedSegmentIndex = 0; 76     } 77     else 78     { 79         self.selfDefiningModel = [self.matchModelTextFiled.text integerValue]; 80     } 81 } 82  83 - (Deck *)createDeck 84 { 85     return [[PlayingCardDeck alloc] init]; 86 } 87  88 - (IBAction)touchRestartButton 89 { 90     //恢復默認值 91     self.gameModelSelectSegmented.enabled = YES; 92     self.matchModelTextFiled.enabled = YES; 93     self.matchModelTextFiled.enabled = YES; 94     self.gameModelSelectSegmented.selectedSegmentIndex = 0; 95     self.selfDefiningModel = 2; 96     self.gameModelLable.text = [NSString stringWithFormat:@"game model:%d",_selfDefiningModel]; 97     self.matchModelTextFiled.text = nil; 98      99     self.game = nil;100     [self updateUIWithNotCreateGame];101 }102 103 - (IBAction)touchCardButton:(UIButton *)sender104 {105     //游戲開始后禁用模式選擇功能106     self.gameModelSelectSegmented.enabled = NO;107     self.matchModelTextFiled.enabled = NO;108     self.matchModelTextFiled.enabled = NO;109     110     NSUInteger cardIndex = [self.cardButtons indexOfObject:sender];111     if(!self.game)112     {113         self.game = [[PlayingCardMatchingGame alloc] initWithCardCount:[self.cardButtons count]114                                                              usingDeck:[self createDeck]];115         self.game.gameModel = self.selfDefiningModel;116     }117     [self.game chooseCardAtIndex:cardIndex];118     [self updateUI];119 }120 121 - (void) updateUIWithNotCreateGame122 {123     for (UIButton *cardButton in self.cardButtons)124     {125         [cardButton setTitle:@"" forState:UIControlStateNormal];126         [cardButton setBackgroundImage:[UIImage imageNamed:@"cardBack"] forState:UIControlStateNormal];127         cardButton.enabled = YES;128     }129     self.gameStateLable.text = @"State";130     self.scoreLable.text = @"Score:0";131 }132 133 - (void)updateUI134 {135     [super updateUI];136     self.gameStateLable.text = ((PlayingCardMatchingGame *)self.game).gameState;137 }138 139 - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event140 {141     [self.view endEditing:YES];142 }143 144 @end

SetCardGameViewController

  本類實現了SetCard匹配游戲,因為是UI層,因此使用了NSAttributeString來表示SetCard的內容,同樣也實現了History功能

  注意:由于SetCard牌面始終朝上,因此要在ViewDidLoad中初始化game

1 #import "ViewController.h"2 3 @interface SetCardGameViewController : ViewController4 5 @end
  1 #import "SetCardGameViewController.h"  2 #import "SetCardMatchingGame.h"  3 #import "SetCardDeck.h"  4 #import "SetCard.h"  5 #import "HistoryViewController.h"  6   7 @interface SetCardGameViewController()  8   9 @property (weak, nonatomic) IBOutlet UILabel *gameStateLable; 10 @property (weak, nonatomic) IBOutlet UIButton *restartButton; 11 @property (nonatomic) NSUInteger selfDefiningModel; 12 @property (nonatomic,strong) NSDictionary *colorOfCard; 13  14 @end 15  16 @implementation SetCardGameViewController 17  18 #define CORNER_FONT_STANDARD_HIGHT 180.0 19 #define CORNER_RADIUS 12.0 20  21 //讓界面變得更好看的魔法 22 - (CGFloat)cornerScaleFactor:(CGFloat)height {return height / CORNER_FONT_STANDARD_HIGHT;} 23 - (CGFloat)cornerRadius:(CGFloat)height {return CORNER_RADIUS * [self cornerScaleFactor:height];} 24  25 - (void)viewDidLoad 26 { 27     //又是個讓界面變得更好看的魔法 28     self.restartButton.layer.cornerRadius = [self cornerRadius:self.restartButton.bounds.size.height]; 29      30     self.colorOfCard = @{@"red" : [UIColor redColor], @"green" : [UIColor greenColor], @"purple" : [UIColor purpleColor]}; 31      32     _selfDefiningModel = 3;//default model 33      34     if(!self.game) 35     { 36         self.game = [[SetCardMatchingGame alloc] initWithCardCount:[self.cardButtons count] 37                                                          usingDeck:[self createDeck]]; 38         self.game.gameModel = self.selfDefiningModel; 39     } 40     [self updateUIWithNotCreateGame]; 41 } 42  43 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 44 { 45     if ([segue.identifier isEqualToString:@"show SetCardGameHistory"]) 46     { 47         if ([segue.destinationViewController isKindOfClass:[HistoryViewController class]]) 48         { 49             HistoryViewController *HVC = (HistoryViewController *)segue.destinationViewController; 50             HVC.history = self.game.gameStateHistory; 51         } 52     } 53 } 54  55  56 - (Deck *)createDeck 57 { 58     return [[SetCardDeck alloc] init]; 59 } 60 - (IBAction)touchCardButtons:(UIButton *)sender 61 { 62     //游戲開始后禁用模式選擇功能 63     NSUInteger cardIndex = [self.cardButtons indexOfObject:sender]; 64     if(!self.game) 65     { 66         self.game = [[SetCardMatchingGame alloc] initWithCardCount:[self.cardButtons count] 67                                                              usingDeck:[self createDeck]]; 68         self.game.gameModel = self.selfDefiningModel; 69     } 70     [self.game chooseCardAtIndex:cardIndex]; 71     [self updateUI]; 72 } 73  74 - (IBAction)touchRestartButton:(UIButton *)sender 75 { 76     //恢復默認值 77     self.selfDefiningModel = 3; 78     self.game = nil; 79     if(!self.game) 80     { 81         self.game = [[SetCardMatchingGame alloc] initWithCardCount:[self.cardButtons count] 82                                                          usingDeck:[self createDeck]]; 83         self.game.gameModel = self.selfDefiningModel; 84     } 85     [self updateUIWithNotCreateGame]; 86 } 87  88 - (void) updateUIWithNotCreateGame 89 { 90     for (UIButton *cardButton in self.cardButtons) 91     { 92         NSUInteger cardIndex = [self.cardButtons indexOfObject:cardButton]; 93         Card *card = [self.game cardAtIndex:cardIndex]; 94         [cardButton setAttributedTitle:[self attributeTitleForCard:card] forState:UIControlStateNormal]; 95         [cardButton setBackgroundImage:[UIImage imageNamed:@"cardFront"] forState:UIControlStateNormal]; 96         cardButton.enabled = YES; 97     } 98     self.gameStateLable.text = @"State"; 99     self.scoreLable.text = @"Score:0";100 }101 102 - (void)updateUI103 {104     for (UIButton *cardButton in self.cardButtons)105     {106         NSUInteger cardIndex = [self.cardButtons indexOfObject:cardButton];107         Card *card = [self.game cardAtIndex:cardIndex];108         [cardButton setAttributedTitle:[self attributeTitleForCard:card] forState:UIControlStateNormal];109         [cardButton setBackgroundImage:[self backgroundImageForCard:card] forState:UIControlStateNormal];110         cardButton.enabled = !card.isMacthed;111     }112     self.scoreLable.text = [NSString stringWithFormat:@"Score:%ld",(long)self.game.score];113     self.gameStateLable.text = ((SetCardMatchingGame *)self.game).gameState;114 }115 116 - (NSAttributedString *)attributeTitleForCard:(Card *)card117 {118     NSShadow *shadow1 = [[NSShadow alloc] init];119     shadow1.shadowColor = [UIColor grayColor];120     shadow1.shadowOffset = CGSizeMake(2.0f, 2.0f);121     122     NSShadow *shadow2 = [[NSShadow alloc] init];123     shadow2.shadowColor = [UIColor whiteColor];124     shadow2.shadowOffset = CGSizeMake(0.0F,0.0f);125     return [[NSAttributedString alloc] initWithString:((SetCard *)card).suit126                                            attributes:@{NSForegroundColorAttributeName : [self.colorOfCard valueForKey:((SetCard *)card).color],127                                                                  NSShadowAttributeName : ((SetCard *)card).shading ? shadow1 : shadow2,128                                                                    NSFontAttributeName : [UIFont boldSystemFontOfSize:10.0f]}];129 }130 131 - (UIImage *)backgroundImageForCard:(Card *)card132 {133     return card.chosen ? [UIImage imageNamed:@"setCardback"] : [UIImage imageNamed:@"cardFront"];134 }135 136 @end

d.history功能的實現

  HistoryViewController

    屬性history用于接收父MVC傳來的數據

1 #import <UIKit/UIKit.h>2 3 @interface HistoryViewController : UIViewController4 @property (strong, nonatomic) NSArray *history;5 @end
 1 #import "HistoryViewController.h" 2  3 @interface HistoryViewController () 4 @property (weak, nonatomic) IBOutlet UITextView *HistoryTextView; 5 @end 6  7 @implementation HistoryViewController 8  9 - (void)viewDidLoad {10     [super viewDidLoad];11     // Do any additional setup after loading the view.    12     for (NSString *state in self.history)13     {14         self.HistoryTextView.text = [self.HistoryTextView.text stringByAppendingFormat:@"%@/n",state];15     }16 }17 @end

  總結:本次作業提出的問題比解決的問題要多很多,作者只是極其簡單的實現了作業的大致要求,仍然有許多問題沒有解決,如Model的抽象化問題中原有的readonly屬性在超類中可能變為了readwrite,是否會產生安全性問題,有沒有更好的方法;Controller的抽象化中將許多原本隱藏在.m文件中的輸出口放至超類的.h文件中,是否會造成子類對輸出口的濫用,有沒有更好的解決方案;仍然沒有解決State顯示內容超出屏幕空間的問題(太懶了=_=);Setcard的state顯示可以使用NSAttributeString(感興趣可以試試);同樣SetCard中history的顯示也可以使用NSAttributeString,此時可能要改變一些傳值的內容(感興趣去玩耍一下吧);關于SetCard的游戲規則其實還不太完善,比如初始化后可能無適合匹配情況的判斷(百度百科的游戲規則中是要再次添加三張牌,我在屏幕中盡可能多添加了幾張紙牌來避免這種情況),以及游戲結束情況的判斷,本次作業相當于只實現了setcard選擇后的匹配計分規則(任重而道遠。。。)。到此就是我大概能想到的值得改進的地方(感覺到提出的問題比解決的問題多了吧=_=),一次作業的內容不僅能復習到前面所學的內容,還是對個人學到知識融匯貫通的一次檢驗,各位加油,有任何問題歡迎討論:)

作業源碼地址:https://github.com/NSLogMeng/Stanford_iOS7_Study/commit/0bb1103ccb4293caa9dc3b12200ba9fb12a51170

課程視頻地址:網易公開課:http://open.163.com/movie/2014/1/L/H/M9H7S9F1H_M9H801GLH.html

       或者iTunes U搜索standford課程


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 97精品国产高清在线看入口 | 看免费的毛片 | 精品国产一区二区三区久久久蜜月 | 欧美黄色免费视频 | 石原莉奈日韩一区二区三区 | 日韩a毛片免费观看 | a视频网站| 麻豆传传媒久久久爱 | 成人在线观看网 | 91成人影院| 久久精品日产第一区二区三区 | 黄色特级视频 | 性高潮一级片 | 在线看毛片的网站 | 一区二区久久电影 | 青青草免费观看 | 九色国产| 鲁丝片一区二区三区免费入口 | 亚洲免费观看视频 | 极品一级片 | 欧美 亚洲 视频 | 2021国产精品 | 国产精品爱久久久久久久 | 羞羞的视频免费在线观看 | 久国产| 欧美一级做性受免费大片免费 | 亚洲成人高清电影 | 亚洲精中文字幕二区三区 | 久久久三区 | 亚洲第一成人在线视频 | 欧美精品一级 | 日本黄色a视频 | 九九精品在线播放 | 国产午夜精品久久久久久免费视 | 少妇一级淫片免费放播放 | 亚洲日韩精品欧美一区二区 | 超碰99在线观看 | 日本va在线观看 | 久久综合伊人 | 看一级毛片 | 日本在线看片 |