IOS学习日志(Controller)1.3

来源:互联网 发布:全能抽奖软件注册码 编辑:程序博客网 时间:2024/06/05 05:36

1.MVC设计模式,MVVM
预备:设计模式

M:Model 模型    数据模型(存数据的结构)    业务模型(多线程、文件存储、网络数据解析等等) V:View 视图    展示数据C:Controller 控制器    在M和C之间控制数据的传递

2.体会MVC的练习:纸牌对对碰
阶段一:
搭建出界面,并且实现,在界面中点击时,能够知道点击的牌的位置

阶段二:
1.分几个类,存哪些数据
第一个类:每一张纸牌的数据Card(数据模型)
第二个类:扑克牌类(数据模型)
第三个类:游戏规则类(Game)(业务模型)

2.随机出12张牌,将12张牌的数据显示到界面上
定义Card类
定义Poker类
定义Game类
在控制器中,创建了poker和game的实例
更新界面方法中:
遍历按钮,找到按钮对应的纸牌,将纸牌的花色+大小
阶段三:
核心业务:点击后对纸牌的比对

阶段四:
统计分数:

涉及到的其他知识点:
a.懒加载lazy loading
某一个存储数据的空间,不要一早就分出来,直到不得不使用这块空间存储数据时再分配,什么时候第一次用这块空间了,再分配,尽量晚分配
b,随机整数
使用C语言的一个函数arc4random()
随机的范围:[0~4个字节表示的最大整数]

content in GameViewController.m

#import "GameViewController.h"#import "Card.h"#import "Poker.h"#import "Game.h"@interface GameViewController ()@property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *allButtons;//增加两个属性,用于模拟游戏,和使用到扑克@property(nonatomic,strong)Poker *poker;@property(nonatomic,strong)Game *game;@property (weak, nonatomic) IBOutlet UILabel *scoreLabel;@end@implementation GameViewController- (void)viewDidLoad {    [super viewDidLoad];    //1.初始化全新的扑克牌    self.poker=[[Poker alloc]init];    //2.创建游戏    self.game=[[Game alloc]initWithPoker:self.poker forCardCount:self.allButtons.count];    //3.更新界面    [self updateView];    // Do any additional setup after loading the view from its nib.}- (IBAction)clickButton:(UIButton *)sender {    //1.查找该按钮对应的下标    NSInteger index=[self.allButtons indexOfObject:sender];//所点的那个位置下标//    2.通知游戏类,本次点击的纸牌的位置    [self.game tapCardAtIndex:index];    //3.根据game改完的数据,刷新界面    [self updateView];}//更新界面-(void)updateView{    //更新分数的显示    self.scoreLabel.text=[NSString stringWithFormat:@"分数:%ld",self.game.score];    //遍历所有按钮,按照按钮的下标,去游戏中找到下标对应的纸牌,然后将纸牌信息显示到按钮上    for (int i=0; i<self.allButtons.count; i++) {        //根据下标找到该位置的纸牌        Card *card=self.game.allRandomCards[i];        //根据下标找到该位置的按钮        UIButton *button=self.allButtons[i];        //根据纸牌的状态,决定按钮上显示的背景图        [button setBackgroundImage:[UIImage imageNamed:[self imageNameForCard:card]] forState:UIControlStateNormal];        //根据纸牌的状态,决定按钮上显示的文字        [button setTitle:[self titleForCard:card]  forState:UIControlStateNormal];        //根据纸牌的是否被匹配,决定按钮是否可用        //card      matched     YES     NO        //button    enabled     NO      YES        button.enabled=!card.isMatched;    }}//依据传入的纸牌对象,返回要加载的图片名称-(NSString*)imageNameForCard:(Card*)card{    return card.isFaceUp?@"cardfront.png":@"cardback.png";}//根据传入的纸牌对象,返回要显示的按钮的文字信息-(NSString*)titleForCard:(Card*)card{    return card.isFaceUp?card.cardInfo:@"";}@end

content in Card.h

#import <Foundation/Foundation.h>/* 类型:纸牌类 属性: 花色:suit 大小:rank 是否面儿朝上:faceUp 是否已匹配:matched */@interface Card : NSObject@property (nonatomic,strong)NSString *suit;//strong和copy的区别@property (nonatomic,strong)NSString *rank;@property (nonatomic,getter=isFaceUp)BOOL faceUp;@property (nonatomic,getter=isMatched)BOOL matched;//增加一个属性,用于存储牌面信息(花色+大小)//增加此属性的目的,是为了方便外接访问花色+大小的信息@property (nonatomic,strong,readonly)NSString *cardInfo;/*自定义的构造方法,创建的同时,指定好花色和大小*/-(instancetype)initWithSuit:(NSString*)suit andRank:(NSString*)rank;+(NSArray *)allsuits;//类方法存储花色的数组+(NSArray *)allranks;//用来返回合法的大小@end

content in Card.m

#import "Card.h"@implementation Card-(instancetype)initWithSuit:(NSString *)suit andRank:(NSString *)rank{    self=[super init];    if (self) {        self.suit=suit;//_suit代表直接访问变量,self.suit会多走一次setter方法        self.rank=rank;        self.faceUp=NO;        self.matched=NO;    }    return self;}/*目标:在给suit或rank赋值时,数据非法,则不能存入属性中 措施:重写属性的setter方法,先判断数据是否合法,再存入到实例变量中 通用规则:如何符合“一给xxx属性赋值,就要做xxx”这样的句式,那么就可以通过重写setter方法,捕获赋值这个时机,实现操作 */-(void)setSuit:(NSString *)suit{    if ([[Card allsuits] containsObject:suit]) {        _suit=suit;    }}-(void)setRank:(NSString *)rank{    if ([[Card allranks] containsObject:rank]) {        _rank=rank;    }}//为cardInfo属性说明返回信息是什么-(NSString *)cardInfo{    return [self.suit stringByAppendingString:self.rank];}//返回所有合法的花色+(NSArray *)allsuits{    return @[@"♠️",@"♥️",@"♣️",@"♦️"];}//返回所有合法的大小+(NSArray *)allranks{    return @[@"A",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"J",@"Q",@"K"];}@end

content in Poker.h

#import <Foundation/Foundation.h>/* Poker:一副扑克牌类 作用:能够存储52张标准的card对象即可 属性:NSMutableArray     allCards */@interface Poker : NSObject@property (nonatomic,strong) NSMutableArray* allCards;@end

content in Poker.m

#import "Poker.h"#import "Card.h"@implementation Poker//重写系统提供的allCards属性的getter方法,懒加载的应用//目的什么时候用到了数组属性才为数组分配空间-(NSMutableArray *)allCards{    // !_allCards 等价于 _allCards==nil    if (!_allCards) {        _allCards=[NSMutableArray array];    }    return _allCards;}//一创建扑克实例时,就应该立即准备好52张纸牌对象//放入到allCards数组中-(instancetype)init{    self=[super init];    //self 等价于self!=nil    if (self) {        NSArray *allSuits=[Card allsuits];        NSArray *allRanks=[Card allranks];        for (NSString *suit in allSuits) {            for (NSString *rank in allRanks) {                Card *card=[[Card alloc]initWithSuit:suit andRank:rank];                [self.allCards addObject:card];            }        }    }    return self;}@end

content in Game.h

#import <Foundation/Foundation.h>#import "Poker.h"/* Game:游戏类 作用: 1.在游戏开始时,能够依靠指定的扑克牌,随机抽取出所需的纸牌 2.在点击某张牌时,根据业务原则进行比对 属性: 1.为了存储随机出来的纸牌,有一个可变数组 allRandomCards */@interface Game : NSObject//记录分数的属性@property(nonatomic)NSInteger score;@property(nonatomic,strong)NSMutableArray * allRandomCards;//依靠传入的poker和count,决定当游戏开始时在哪个对象中,抽取多少张牌-(instancetype)initWithPoker:(Poker *)poker forCardCount:(NSInteger)count;//@property(nonatomic,strong)Poker *poker;//核心业务逻辑:根据传入的点击位置,进行比对-(void)tapCardAtIndex:(NSInteger)index;@end

content in Game.m

#import "Game.h"#import "Card.h"@implementation Game//重写allRandomCards的getter方法,保证在使用数组时空间存在-(NSMutableArray *)allRandomCards{    if (!_allRandomCards) {        _allRandomCards=[NSMutableArray array];    }    return _allRandomCards;}/* 参数1:poker 要抽取的纸牌的 参数2:cardsCount 要抽取的纸牌的个数 */-(instancetype)initWithPoker:(Poker *)poker forCardCount:(NSInteger)count{    self=[super init];    if (self) {        //随机抽取纸牌        for (int i=0; i<count; i++) {            //1.先随机出一个下标            NSInteger index=arc4random()%poker.allCards.count;            //2.按照这个下标去poker中找到这个位置的纸牌            Card *card=poker.allCards[index];            //将随机到的这张牌从原油的poker中移除            [poker.allCards removeObjectAtIndex:index];            //3.将这张牌放入到用于保存随机牌的allRandomCards数组中            [self.allRandomCards addObject:card];        }    }    return self;}/* 1.根据点击的位置,找到对应的纸牌对象 2.如果这张牌,面朝上,那么就翻下来 3.否则    a.先将牌翻成面朝上    b.本张牌与剩下的,已经翻上来,且,没有被匹配的进行比对        1.如果花色相同            两张牌修改为已经被匹配        2.否则,如果,大小相同            两张牌修改为已经被匹配        3.否则            将被比较的那张牌翻成背朝上 */-(void)tapCardAtIndex:(NSInteger)index{    Card *chooseCard=self.allRandomCards[index];    if (chooseCard.isFaceUp) {        chooseCard.faceUp=NO;    }    else{        chooseCard.faceUp=YES;        for (int i=0; i<self.allRandomCards.count; i++)        {            if(i!=index)            {                Card *otherCard=self.allRandomCards[i];                if (otherCard.isFaceUp&&!otherCard.isMatched)                {                    if ([chooseCard.suit isEqualToString:otherCard.suit])                    {                        chooseCard.matched=YES;                        otherCard.matched=YES;                        //花色相同计1分                        self.score+=1;                    }                    else if([chooseCard.rank isEqualToString:otherCard.rank])                    {                        chooseCard.matched=YES;                        otherCard.matched=YES;                        //大小相同计4分                        self.score+=4;                    }                    else                    {                        otherCard.faceUp=NO;                    }                }            }        }    }}@end
0 0