斯坦福大学iOS开发公开课总结(二) :翻纸牌Demo

本节课简单介绍了控件的懒加载(lazy instantiation),数组,字典,类方法的使用,在最后展示了翻转卡牌的小demo。

懒加载(lazy instantiation)


懒加载:在实例变量被使用之前的那一刻初始化。防止大量的实例变量(属性)在同一时间初始化(尤其是不用将创建对象的方法全部写在viewDidLoad:方法里)。

@interface ViewController ()

@property (nonatomic, strong) NSMutableArray *cards;

@end

@implementation ViewController

- (NSMutableArray *)cards
{
    //如果此实例变量为空,则初始化;否则,直接调用
    if (!_cards) {
        _cards = [[NSMutableArray alloc] init];
    }
    return _cards;
}

@end

数组的使用


在可变数组中插入元素

在数组中插入元素是可变数组的方法,因为不可变数组在初始化以后就无法再更改。
尤其注意的是:在数组中插入元素时,插入的元素必须不能为空,否则会引起程序崩溃。需要对要插入的元素做是否为空的判断!

- (void)addCard: (Card *)card atTop:(BOOL)atTop
{
    if (atTop) {
        
        //插入到数组第一个位置
        [self.cards insertObject:card atIndex:0];
    
    }else{
        
        //添加到数组末尾
        [self.cards addObject:card];
    
    }
}

在可变数组中引用和移除数组元素

在数组中,提取和移除元素的时候需要注意的是需要判断数组是否为空,如果在数组为空的情况下引用或移除某个元素会引起程序的崩溃! 所以要先进行目标数组元素数量判断。

- (Card *)drawRandomCard
{
    //如果数组为空数组,则直接放回nil,因为没有可以抽取的元素。
    Card *randomCard = nil;
    
    //判断数组元素个数是否不为0,如果为0,则返回nil
    if ([self.cards count]) {
        
        //生成0到[self.cards count]-1的随机数
        NSUInteger index = arc4random() % [self.cards count];
        
        //引用下标为index的元素
        randomCard = self.cards[index];
        
        //移除下标为index的元素
        [self.cards removeObjectAtIndex:index];
        
    }
    
    return randomCard;
}

类方法


类方法也叫工厂方法,类方法主要包括两种:

  1. 类的初始化:形成类的实例。
  2. 工具方法:不经过实例化获得某些数据。

应用:用类方法生成四种不同花色:

+ (NSArray *)ValidSuits
{
    return @[@"♥︎",@"♦︎",@"♣︎",@"♠︎"];
}

- (void)setSuit:(NSString *)suit
{
    if ([ [PlayingCard ValidSuits] containsObject:suit]) {
        _suit = suit;
    }
}

instancetype


instancetype的使用目的是确保返回的对象同这条消息要发送到的对象一样。

怎么说?

常用在类的初始化方法的返回值中,因为如果类的初始化返回值是id,那么这个指针可以指向任何对象,所以有可能指向非此类的对象类型;

所以,instancetype作为初始化方法的返回值后,那么初始化的结果一定会同此类的类型一致。

举个:

- (instancetype)init
{
    //检查父类是否初始化成功
    self = [super init];
    
    if (self) {
        //初始化代码
    }
    
    return self;
}

翻牌Demo


设计需求:

在界面上显示一张扑克牌,点击后翻牌:如果是正面,点击后就显示背面;如果是背面,点击后显示正面。

效果图:

斯坦福大学iOS开发公开课总结(二) :翻纸牌Demo_第1张图片
左:纸牌背面;右:纸牌正面

实现代码:

1. 点击按钮翻牌

- (IBAction)touchCardButton:(UIButton *)sender {
    
    //先判断牌面:如果按钮的title有字,则为正面
    if ([sender.currentTitle length]) {
       
        //1. 背面的UI效果:
        
        //1.1 设置背景图片为背面的图片
        [sender setBackgroundImage:[UIImage imageNamed:@"cardBack"] forState:UIControlStateNormal];
       
        //1.2 设置按钮title为空,因为要翻到背面
        [sender setTitle:@"" forState:UIControlStateNormal];
        
    }else{
        
        //2. 正面的UI效果:
      
        //2.1 设置背景图片为空
        [sender setBackgroundImage:[UIImage imageNamed:@""] forState:UIControlStateNormal];
        
        //2.2 设置背景颜色为白色
        [sender setBackgroundColor:[UIColor whiteColor]];
       
        //2.3 设置按钮title为牌的花色
        [sender setTitle:@"A♣︎" forState:UIControlStateNormal];
    }
    
    //翻牌次数记录。同时存在setter和getter方法。首先getter方法取到当前的翻拍次数,然后用setter方法让翻拍次数+1
    self.flipCount++;
}

2. 更新按钮UI

更新按钮的UI的代码放到了属性flipCount的setter方法里。

- (void)setFlipCount:(int)flipCount
{
    _flipCount = flipCount;
    
    //在setter方法完成后,设置标签的显示数字
    self.flipsLabel.text = [NSString stringWithFormat:@"Flips: %d", self.flipCount];
}

但是笔者个人认为这种处理方式并不好,因为一个方法最好只做一件事情,所以应该将更新按钮UI的代码单独提取出来作为另一个方法:

- (IBAction)touchCardButton:(UIButton *)sender {
    
    //先判断牌面:如果按钮的title有字,则为正面
    if ([sender.currentTitle length]) {
       
        //背面的UI效果
        [sender setBackgroundImage:[UIImage imageNamed:@"cardBack"] forState:UIControlStateNormal];
        [sender setTitle:@"" forState:UIControlStateNormal];
        
    }else{
        
        //正面的UI效果
        [sender setBackgroundImage:[UIImage imageNamed:@""] forState:UIControlStateNormal];
        [sender setBackgroundColor:[UIColor whiteColor]];
        [sender setTitle:@"A♣︎" forState:UIControlStateNormal];
    }
    
    //翻牌次数+1。
    self.flipCount++;
    
    //更新Label显示的数字
    [self updateFlipsLabel];
}

/**
 *  单独提取出更新Label显示的数字的方法
 */
- (void)updateFlipsLabel
{
     self.flipsLabel.text = [NSString stringWithFormat:@"Flips: %d", self.flipCount];
}

这样一来,程序的可读性更高了一点。而且我们还不用重写flipsCount的setter方法。

本文已在版权印备案,如需转载请访问版权印。48422928

获取授权

-------------------------------- 2018年7月17日更新 --------------------------------

注意注意!!!

笔者在近期开通了个人公众号,主要分享编程,读书笔记,思考类的文章。

  • 编程类文章:包括笔者以前发布的精选技术文章,以及后续发布的技术文章(以原创为主),并且逐渐脱离 iOS 的内容,将侧重点会转移到提高编程能力的方向上。
  • 读书笔记类文章:分享编程类思考类心理类职场类书籍的读书笔记。
  • 思考类文章:分享笔者平时在技术上生活上的思考。

因为公众号每天发布的消息数有限制,所以到目前为止还没有将所有过去的精选文章都发布在公众号上,后续会逐步发布的。

而且因为各大博客平台的各种限制,后面还会在公众号上发布一些短小精干,以小见大的干货文章哦~

扫下方的公众号二维码并点击关注,期待与您的共同成长~

斯坦福大学iOS开发公开课总结(二) :翻纸牌Demo_第2张图片
公众号:程序员维他命

你可能感兴趣的:(斯坦福大学iOS开发公开课总结(二) :翻纸牌Demo)