斯坦福大学IOS7开发课程2
这节课就着手开始实现”Card Matching Game”,纸牌匹配游戏。
具体来说就是实现涉及的各种类,以及XCode的简单使用。
Card类
下面代码是课程1结束时的Card类,包括Card.h和Card.m:
| 1 | // Card.h | 
| 1 | // Card.m | 
Deck类
这节课首先添加另外一个类:整幅牌Deck,下面是上节课学的类的基本结构
| 1 | // Deck.h | 
| 1 | // Deck.m | 
接下来为Deck类添加两个基础的方法:
- 向Deck中添加牌的addCard,其中atTop表示是否将新的牌放在牌堆的顶部。
- 另一个是从Deck中随机抽取牌的drawRandomCard:
| 1 | // Deck.h | 
如果希望addCard的参数atTop是可选参数,在Objective-C中唯一的方法就是声明一个新的函数,这个函数也叫addCard,但是没有参数atTop。这两个addCard是两个不同的函数,相互之间并没有关联。
| 1 | // Deck.h | 
为了存储牌堆中的牌,需要在私密API中添加一个属性,类型是可变数组NSMutableArray。mutable意味着可以向数组中添加或删除数据,而普通的NSArray是不能修改的,一旦被建立,不能添加数据也不能删除。
在Objective-C中声明数组没办法指定数据类型。
| 1 | // Deck.m | 
根据上节课说到构建属性时自动生成的getter和setter,新建一个Deck类后,其所有的变量和属性都会被自动初始化为0/nil,属性cards是一个空指针,因此调用addCard时虽然不会导致程序的崩溃,但是也不能正常工作。
那么怎么解决这个问题呢?方法是重写属性的getter函数,在getter中添加一个判断结构,属性cards自动生成的getter是:
| 1 | - (NSMutableArray *)cards | 
为了在其中添加一个判断逻辑,需要手动重写这个getter:
| 1 | // Deck.m | 
接下来实现drawRandomCard
| 1 | // Deck.m | 
至此,Deck类已经完成。
PlayingCard类
接下来再添加一个类:PlayingCard,同样的,基本结构如下:
| 1 | // PlayingCard.h | 
| 1 | // PlayingCard.m | 
给类添加两个属性suit和rank,前者表示牌的花色“桃(hearts)”、“(方片)diamons”、“(梅花)clubs”,后者表示1到13。另外在.m文件中,重写父类属性content的getter。
| 1 | // PlayingCard.h | 
| 1 | // PlayingCard.m | 
注意到,字符串前面有个@,这表示把字符串变成一个字符串类。其中%@表示一个对象,当然可以是字符串。
重写父类属性contents的getter之后,获取contents内容会返回“数字 + 花色”,比如“3红桃”、“1梅花”、“13方片”等。但是在纸牌中,我们一般会把1说成A,11说成J等……,为了符合这个习惯,上面的contents重写可以改成下面的代码:
| 1 | // PlayingCard.m | 
将rank的0设置为”?“是因为objective-C默认将rank初始化为0,”?“表示这是未知的,没有经过设置的。那如果花色没经过设置也会显示”?“就更好了,解决方法也是重写suit属性的getter函数。
| 1 | // PlayingCard.m | 
suit的选择应该只有四种,为了防止suit被设置为其他值,还要重写suit属性的setter:setSuit
| 1 | // PlayingCard.m | 
值得注意的是,setSuit中的第一个@表示创建新的数组,在这里,每次判断都会新建这个数组。为了性能和代码简介,可以新建函数来判断setter收到的suit是否有效。实际上,这种改变对性能的提升是极其有限的。
| 1 | // PlayingCard.m | 
这里在函数实现前面第一次出现了+符号,这个符号表示这个函数是类的函数(而不是对象的函数)。
一般只在两种情况下使用类的函数:
- 工具函数(utility method),比如这里的 - validSuits。
- 创建类的函数,比如 - stringWithFormat。- 对rank属性做同样的检查和优化,并添加一个公开API - maxRank返回rank的最大值,比如现在是13。
| 1 | // PlayingCard.h | 
| 1 | // PlayingCard.m | 
PlayingCardDeck类
接下来可以开始玩牌了,创建一个新的类PlayingCardDeck,继承自Deck类,但是需要重写构造函数:
| 1 | // PlayingCardDeck.h | 
| 1 | // PlayingCardDeck.m | 
XCode的简单使用
课程剩余的部分就是以纸牌游戏为例,简单介绍XCode的使用,开发一个简单的App,App内容是显示纸牌,点击纸牌将其翻转。
由于课程介绍的是XCode 5,笔者记笔记的时候已经是XCode 12.4了,有了不小的变化,参考笔者另一篇笔记(Objective-C IOS开发之HelloWorld),应该也不难完成,就不再具体介绍实现了。
相较于HelloWorld这个App,课程中实现的App另外涉及了以下知识点:
- 图像添加 - 直接将图片拖到 - Assets.xcassets文件夹中
- button背景图片的设置 - 点击button,在属性中点击 - Background下拉菜单,就会显示上一步添加的图片选项,以及一些原始icon。
- Action中的sender其实就是触发事件的View对象 
- 类的添加 - 添加类的方法,XCode 12中其实就是新建 - Cocoa Touch Class。