前言:还记得上次写swift第一周学习总结,现在想起来仿佛就是昨天写的一样,是那么清晰,时间是那么的快。因为专注,所以时间飞逝,又到了我来跟大家分享我的又一周学习经验了。小司机要开动了,各位成员小伙伴们专注一些,时间就要起飞了....
1.jpg
集合(Set)
集合是一种存储无序的,值唯一的数据结构。是用哈西码(hash code),或者叫散列码的方式进行存储数据.当你向一个集合中添加同样的数据时,数据不会被添加,言外之意也就是集合中不存在相同的两个或多个数据。
var a:Set<Int> = [1,2,3,1,2,5] //创建一个集合,创建时可以写多个相同数据进去
print(a) //显示集合内容:[5, 2, 3, 1],但其实集合自己早已经过滤掉了相同的数据,只保留了一个。
集合的很多功能跟我门平常学的数学里的集合很相似:
var b:Set<Int> = [3,5,7,9,11]
//集合的交集(a和b都有的元素)
print(a.intersect(b)) //[5, 3]
//集合的并集(a和b所有的元素)
print(a.union(b)) //[2, 9, 5, 7, 3, 1, 11]
//集合的差集(a有b没有的元素)
print(a.subtract(b)) //[2, 1]
//判断b是不是a的子集
print(b.isSubsetOf(a)) //false
//判断集合是否相交
print(a.isDisjointWith(b)) //false
字典
Swift 字典用来存储无序的相同类型数据的集合,Swift 字典会强制检测元素的类型,如果类型不同则会报错。
Swift 字典每个值(value)都关联唯一的键(key),键作为字典中的这个值数据的标识符。
和数组中的数据项不同,字典中的数据项并没有具体顺序。我们在需要通过标识符(键)访问数据的时候使用字典,这种方法很大程度上和我们在现实世界中使用字典查字义的方法一样。
Swift 字典的key没有类型限制可以是整型或字符串,但必须是唯一的。
如果创建一个字典,并赋值给一个变量,则创建的字典就是可以修改的。这意味着在创建字典后,可以通过添加、删除、修改的方式改变字典里的项目。如果将一个字典赋值给常量,字典就不可修改,并且字典的大小和内容都不可以修改。
创建一个字典
var someDict1 = [KeyType: ValueType]()
//创建一个空字典,键的类型为 Int,值的类型为 String
var someDict2 = [Int: String]()
var someDict3:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
访问字典中的数据
//根据字典的索引来访问数组的元素
var someVar = someDict[key]
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var someVar = someDict[1]
print( "key = 1 的值为 \(someVar!)" )
print( "key = 2 的值为 \(someDict[2]!)" )
print( "key = 3 的值为 \(someDict[3]!)" )
//结果
key = 1 的值为 One
key = 2 的值为 Two
key = 3 的值为 Three
修改字典中的数据
可以使用 updateValue(forKey:) 增加或更新字典的内容。如果 key 不存在,则添加值,如果存在则修改 key 对应的值
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var oldVal = someDict.updateValue("One 新的值", forKey: 1)
var someVar = someDict[1]
print( "key = 1 旧的值 \(oldVal!)" )
print( "key = 1 的值为 \(someVar!)" )
print( "key = 2 的值为 \(someDict[2]!)" )
print( "key = 3 的值为 \(someDict[3]!)" )
//结果
key = 1 旧的值 One
key = 1 的值为 One 新的值
key = 2 的值为 Two
key = 3 的值为 Three
也可以通过指定的 key 来修改字典的值
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var oldVal = someDict[1]
someDict[1] = "One 新的值"
var someVar = someDict[1]
print( "key = 1 旧的值 \(oldVal!)" )
print( "key = 1 的值为 \(someVar!)" )
print( "key = 2 的值为 \(someDict[2]!)" )
print( "key = 3 的值为 \(someDict[3]!)" )
//结果
key = 1 旧的值 One
key = 1 的值为 One 新的值
key = 2 的值为 Two
key = 3 的值为 Three
删除字典中的数据
可以使用 removeValueForKey() 方法来移除字典 key-value 对。如果 key 存在该方法返回移除的值,如果不存在返回 nil
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var removedValue = someDict.removeValueForKey(2)
print( "key = 1 的值为 \(someDict[1]!)" )
print( "key = 2 的值为 \(someDict[2]!)" )
print( "key = 3 的值为 \(someDict[3]!)" )
//结果
key = 1 的值为 One
key = 2 的值为 nil
key = 3 的值为 Three
遍历字典中的数据
可以使用 for-in 循环来遍历某个字典中的键值对
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
for (key, value) in someDict {
print("字典 key \(key) - 字典 value \(value)")
}
//结果
字典 key 2 - 字典 value Two
字典 key 3 - 字典 value Three
字典 key 1 - 字典 value One
也可以使用enumerate()方法来进行字典遍历,返回的是字典的索引及 (key, value) 对
var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
for (key, value) in someDict.enumerate() {
print("字典 key \(key) - 字典 (key, value) 对 \(value)")
}
//结果
字典 key 0 - 字典 (key, value) 对 (2, "Two")
字典 key 1 - 字典 (key, value) 对 (3, "Three")
字典 key 2 - 字典 (key, value) 对 (1, "One")
count 属性
可以使用只读的 count 属性来计算字典有多少个键值对
var someDict1:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var someDict2:[Int:String] = [4:"Four", 5:"Five"]
print("someDict1 含有 \(someDict1.count) 个键值对")
print("someDict2 含有 \(someDict2.count) 个键值对")
//结果
someDict1 含有 3 个键值对
someDict2 含有 2 个键值对
函数
函数用来完成特定任务的独立的代码块,定义函数使用关键字 func。每个函数都有一个函数名来描述它的功能。通过函数名以及对应类型的参数值来调用这个函数。函数的参数传递的顺序必须与参数列表相同。
定义一个函数:
func 函数名(外部参数名 内部参数名:类型,外部参数名 内部参数名:类型) -> 返回类型{ 函数执行体 }
func myMin(a x:Int ,b y:Int) -> Int{
return x < y ? x:y
}
print("最小值为:\(myMin(a: 2,b: 4))")]
//结果
最小值为:2
swift 中函数的参数列表可以是可变参数列表(参数可以是任意多个)
func sum(nums: Int...) -> Int{
var total = 0
for num in nums{
total += num
}
return total
}
print("和为:\(sum())")
print("和为:\(sum(2,3))")
print("和为:\(sum(1,2,3))")
print("和为:\(sum(1,2,3,4,5,6,7,89,90,10))")
//结果
和为:0
和为:5
和为:6
和为:217
可以用一个元组(tuple)返回多个数据
func minMax(array: [Int]) -> (min: Int, max: Int)?{
if array.isEmpty { return nil }
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let b = minMax([32,22,50,69]){
print("最小值:\(b.min)")
print("最大值:\(b.max)")
}
else{
print("数组中没有元素!")
}
//结果
最小值:22
最大值:69
不带参数函数
func funcname() -> datatype {
return datatype
}
没有返回值函数
func runoob(site: String) {
print("你好!:\(site)")
}
runoob("wangyou")
//结果
你好!wangyou
外部参数名
可以在局部参数名前指定外部参数名,中间以空格分隔,外部参数名用于在函数调用时传递给函数的参数
func pow(firstArg a: Int, secondArg b: Int) -> Int {
var res = a
for _ in 1..<b {
res = res * a
}
print(res)
return res
}
pow(firstArg:5, secondArg:3)
//结果
125
函数类型作为参数类型、函数类型作为返回类型
可以将函数作为参数传递给另外一个参数
func sum(a: Int, b: Int) -> Int {
return a + b
}
var addition: (Int, Int) -> Int = sum
print("输出结果: \(addition(40, 89))")
func another(addition: (Int, Int) -> Int, a: Int, b: Int) {
print("输出结果: \(addition(a, b))")
}
another(sum, a: 10, b: 20)
//结果
输出结果: 129
输出结果: 30
函数嵌套
func calcDecrement(forDecrement total: Int) -> () -> Int {
var overallDecrement = 0
func decrementer() -> Int {
overallDecrement -= total
return overallDecrement
}
return decrementer
}
let decrem = calcDecrement(forDecrement: 30)
print(decrem())
//结果
-30
上面都是对函数等功能的介绍,下面看看一些实用演示实例:
判断 给定的天是该年的第多少天
func daysOfYear(year:Int,_ mouth:Int,_ day:Int) -> Int{
let daysOfMouth = [31,28,31,30,31,30,31,31,30,31,30,31]
var sum = 0
for i in 0..<mouth - 1{
sum += daysOfMouth[i]
}
if isLeapYear(year) && mouth > 2{
print("\(year)是闰年")
sum += 1
}
else{
print("\(year)不是闰年")
}
return sum + day
}
func isLeapYear(year:Int) -> Bool{
return year % 4 == 0 && year % 100 != 0 || year % 400 == 0
}
print("请输入年月日:",terminator:"")
let y = inputInt()
let m = inputInt()
let d = inputInt()
print("\(y)年\(m)月\(d)号,是\(y)的第\(daysOfYear(y, m, d))天")
//运行
请输入年月日:2008 5 6
2008是闰年
2008年5月6号,是2008的第127天
计算组合数 - 阶乘递归方法实现
递归方法使用前提:
1.递归公式
2.收敛条件
func combine(m:Int,_ n:Int) -> Int{
assert(m >= n,"m必须大于等于n")
return Int(factoria(m) / factoria(n) / factoria(m - n))
}
func factoria(n:Int) -> Double{
if n == 0 || n == 1{
return 1
}
return Double(n) * factoria(n - 1)
}
print("请输入m,n的值:",terminator:"")
let j = inputInt()
let k = inputInt()
print("c(\(j),\(k))的值为:\(combine(j,k))")
//运行
请输入m,n的值:5 3
c(5,3)的值为:10
求和 - 递归方法实现
func sum(n:Int) -> Int{
if n == 1{
return 1
}
return n + sum(n - 1)
}
print(sum(100))
//运行
5050
汉诺伊塔 - 递归实现
var i = 1
func hanoi(n:Int,_ a:String,_ b:String,_ c:String){
if n > 0{
hanoi(n - 1,a,c,b)
print("\(i):\(a)-->\(b)")
i += 1
hanoi(n - 1, c, b, a)
}
}
hanoi(5, "a", "b", "c")
//运行
1:a-->b
2:a-->c
3:b-->c
4:a-->b
5:c-->a
6:c-->b
7:a-->b
闭包(简单介绍)
闭包(Closures)是自包含的功能代码块,可以在代码中使用或者用来作为参数传值。
Swift中的闭包有很多优化的地方:
1.根据上下文推断参数和返回值类型
2.从单行表达式闭包中隐式返回(也就是闭包体只有一行代码,可以省略return)
3.可以使用简化参数名,如$0, $1(从0开始,表示第i个参数...)
4.提供了尾随闭包语法(Trailing closure syntax)
func foo(array:[Int],_ fn:(Int,Int) -> Int) ->Int{
var sum = array[0]
for x in array[1..<array.count]{
sum = fn(sum,x)
}
return sum
}
let a = [1,2,3,4,5]
// 当调用foo函数时第二个参数可以传什么?
//1.自定义的(Int,Int) -> Int 类型的函数
//2.传入二元运算符: + - * / % (运算符也都是函数)
//3.传入匿名函数(闭包)
print(foo(a ,+ ))
print(foo(a) {$0 + $1}) //尾随闭包法
print(foo(a, { (a, b) -> Int in return a + b })) //完整闭包写法
print(foo(a, { a, b in a + b })) //省略掉类型和不必要的括号
//运行
15
15
15
15
尾随闭包
如果函数的最后一个参数是闭包可以写成尾随闭包的形式
也就是将闭包放到函数的圆括号外面写一对花括号中
如果函数后面有尾随闭包且函数的圆括号中没有参数
那么函数的圆括号也可以省略(仅限于有尾随闭包的情况)
var array = ["game","abacus","hello","cat","good","mother","father","disco","zhat","young"]
array.sortInPlace() {$0 > $1} // 相当于: array.sortInPlace(>)
array.sortInPlace() { if $0.characters.count == $1.characters.count{
return $0 < $1
}
return $0.characters.count < $1.characters.count
}
//按照字母多少的顺序 进行排列
print(array)
//运行
["cat", "game", "good", "zhat", "disco", "hello", "young", "abacus", "father", "mother"]
数组尾随闭包的使用
let array = [23,45,32,43,55,12,45,66]
// 1.过滤
let newarray1 = array.filter { $0 % 2 == 0 } //{ 条件 }-满足条件的保留下来,不满足的过滤掉 ($0默认表示一个形参)
print(newarray1)
//运行
[32, 12, 66]
// 2.映射 - 对原数组数据进行一定的运算得到一个新数组
let newarray2 = array.map { $0 * $0 }
print(newarray2)
//运行
[529, 2025, 1024, 1849, 3025, 144, 2025, 4356]
// 3.缩减 - 合并数组中的元素
let newarray3 = array.reduce(0, combine: +) // 求和
print(newarray3)
let newarray4 = array.reduce(1, combine: *) //求积
print(newarray4)
let newarray5 = array[1..<array.count].reduce(array[0]){$1 > $0 ? $1:$0 } //取最大值
print(newarray5)
//运行
321
2791638432000
66
let strArray = ["I","Love","You","Forever"] //字符串的缩减(合并)
let array1 = strArray.reduce("") {$0 + " " + $1}
print(array1)
//运行
I Love You Forever
类(重点)
1.发现类
- 在对问题的描述中的名词和动词
- 名词为类或者类中的属性,动词是类中的方法
2.创建类
- 数据抽象(属性)
- 行为抽象(方法)
- 初始化方法
- 访问修饰符
1.public - 公开
2.internal - 内部的 - 默认
3.private - 私有 - 外面不可使用的属性修饰符
存储属性通常是 private 的,因为数据保护起来
方法以一般是public 的 因为方法是对象接受的消息
如果自定义的类没有打算在其他项目中使用 可以不写访问修饰符,直接使用默认的internal修饰符表示的本项目中公开对其他项目私有
步骤1:定义一个类(如果苹果已经提供了你要用的类酒直接到第2步)
class Student{
//变量定义到类的外面就叫变量 - variable
//变量定义到类的里面就叫属性 - property
//数据抽象 - 找到和学生相关的属性(找名词)
var name: String
var age: Int
//初始化方法(构造方法/构造器) - 创建对象要使用的方法
init(name:String,age:Int){
self.name = name
self.age = age
}
//函数写到类的外面就叫函数 - function
//函数写到类的里面就叫方法 - method
//行为抽象 - 找到和学生相关的方法(找动词)
func eat(food:String) -> Void{
print("\(name)正在吃\(food)")
}
func study(courseName:String){
print("\(name)正在学习\(courseName)")
}
func watchJapeneseAV() {
if age >= 18{
print("正在观看电影")
}
else{
print("\(name)未满十八岁")
}
}
}
步骤2:创建对象(调用初始化方法)
let stu1 = Student(name: "张三", age: 35)
步骤3:初始化对象数据
stu1.eat("西瓜 ")
stu1.study("swift程序设计")
stu1.watchJapeneseAV()
实例:
奥特曼打小怪兽
定义一个奥特曼得类
func randomInt(min:UInt32,_ max:UInt32) ->Int{
return Int(arc4random_uniform(UInt32(max - min + 1)) + min )
}
class UItraman{
private var _name :String
private var _Hp:Int
private var _Mp:Int
var isAlive :Bool{
get{
return _Hp > 0
}
}
var name:String{
get{return _name}
}
var Mp:Int{
get{return _Mp}
set{_Mp = newValue > 0 ? newValue : 0}
}
var Hp:Int{
get{return _Hp}
set{_Hp = newValue > 0 ? newValue : 0}
}
init(_name:String,_Hp:Int,_Mp:Int){
self._name = _name
self._Hp = _Hp
self._Mp = _Mp
}
func attack(monster:Monster){
let injury = randomInt(15, 20)
monster.Hp -= injury
_Mp += 5
}
func hugeAttack(monster:Monster){
let injury = 40
monster.Hp -= injury
_Mp -= 40
}
func magicalAttack(monsters:[Monster]){
if self.Mp >= 25{
let injury = 25
for m in monsters{
m.Hp -= injury
}
_Mp -= 25
}
}
}
定义一个小怪兽的类
class Monster{
var name :String
private var _Hp:Int
var isAlive :Bool{
get{
return _Hp > 0
}
}
var Hp:Int {
get{return _Hp}
set{ _Hp = newValue > 0 ? newValue : 0}
}
init(name:String,_Hp:Int){
self.name = name
self._Hp = _Hp
}
func attack(uitraman:UItraman){
let injury = randomInt(10, 15)
uitraman.Hp -= injury
}
}
实现主程序:
let u = UItraman(_name: "迪佳", _Hp: 300, _Mp: 80)
let m = [
Monster(name: "熊大", _Hp: 150),
Monster(name: "熊二", _Hp: 200),
Monster(name: "熊三", _Hp: 250)]
var round = 1
for i in 0..<m.count{
repeat{
print("=====第\(round)回合=====")
var z = Int(arc4random_uniform(10)) + 1
if z <= 9 && z >= 8 && u.Mp >= 25{
u.magicalAttack(m)
print("\(u.name)奥特曼释放魔法群攻技能!")
}
else if z == 10 && u.Mp >= 40 {
u.hugeAttack(m[i])
print("\(u.name)奥特曼释放终极必杀技能!!!")
}
else {
u.attack(m[i])
print("\(u.name)奥特曼释放普通攻击!!!")
}
if m[i].Hp > 0{
m[i].attack(u)
}
print("\(u.name)奥特曼的生命值:\(u.Hp)")
print("\(u.name)奥特曼的魔法值:\(u.Mp)")
print("\(m[i].name)小怪兽的生命值:\(m[i].Hp)")
round += 1
if u.Hp <= 0{
print("\(u.name)奥特曼光荣殉国!!")
print("\(m[i].name)小怪兽胜利!!")
break
}
}while m[i].Hp > 0
}
if u.Hp == 0 && m[m.count - 1].Hp == 0{
print("奥特曼和小怪兽同归于尽!!!")
}
else if u.Hp > 0{
print("\(u.name)奥特曼胜利!!")
}
运行结果
=====第1回合=====
迪佳奥特曼释放终极必杀技能!!!
迪佳奥特曼的生命值:189
迪佳奥特曼的魔法值:40
熊大小怪兽的生命值:60
=====第2回合=====
迪佳奥特曼释放普通攻击!!!
迪佳奥特曼的生命值:176
迪佳奥特曼的魔法值:45
熊大小怪兽的生命值:40
=====第3回合=====
迪佳奥特曼释放普通攻击!!!
迪佳奥特曼的生命值:164
迪佳奥特曼的魔法值:50
熊大小怪兽的生命值:25
=====第4回合=====
迪佳奥特曼释放魔法群攻技能!
迪佳奥特曼的生命值:164
迪佳奥特曼的魔法值:25
熊大小怪兽的生命值:0
=====第5回合=====
迪佳奥特曼释放魔法群攻技能!
迪佳奥特曼的生命值:151
迪佳奥特曼的魔法值:0
熊二小怪兽的生命值:70
=====第6回合=====
迪佳奥特曼释放普通攻击!!!
迪佳奥特曼的生命值:140
迪佳奥特曼的魔法值:5
熊二小怪兽的生命值:50
=====第7回合=====
迪佳奥特曼释放普通攻击!!!
迪佳奥特曼的生命值:125
迪佳奥特曼的魔法值:10
熊二小怪兽的生命值:30
=====第8回合=====
迪佳奥特曼释放普通攻击!!!
迪佳奥特曼的生命值:115
迪佳奥特曼的魔法值:15
熊二小怪兽的生命值:11
=====第9回合=====
迪佳奥特曼释放普通攻击!!!
迪佳奥特曼的生命值:115
迪佳奥特曼的魔法值:20
熊二小怪兽的生命值:0
=====第10回合=====
迪佳奥特曼释放普通攻击!!!
迪佳奥特曼的生命值:104
迪佳奥特曼的魔法值:25
熊三小怪兽的生命值:84
=====第11回合=====
迪佳奥特曼释放普通攻击!!!
迪佳奥特曼的生命值:89
迪佳奥特曼的魔法值:30
熊三小怪兽的生命值:68
=====第12回合=====
迪佳奥特曼释放普通攻击!!!
迪佳奥特曼的生命值:78
迪佳奥特曼的魔法值:35
熊三小怪兽的生命值:52
=====第13回合=====
迪佳奥特曼释放普通攻击!!!
迪佳奥特曼的生命值:64
迪佳奥特曼的魔法值:40
熊三小怪兽的生命值:34
=====第14回合=====
迪佳奥特曼释放魔法群攻技能!
迪佳奥特曼的生命值:51
迪佳奥特曼的魔法值:15
熊三小怪兽的生命值:9
=====第15回合=====
迪佳奥特曼释放普通攻击!!!
迪佳奥特曼的生命值:51
迪佳奥特曼的魔法值:20
熊三小怪兽的生命值:0
迪佳奥特曼胜利!!
分数运算 - 运算符重载
先创建一个类
// x 和 y的最大公约数 跟 y%x 和 x 的最大公约数是一样的 - 短除法(辗转求余数)
func gcd(x:Int,_ y:Int) -> Int{
if x > y {
return gcd(y, x)
}
else if y % x != 0 {
return gcd(y % x, x)
}
else{
return x
}
}
class Fraction {
private var _num:Int
private var _den:Int
var info:String {
get {return _num == 0 || _den == 1 ? "\(_num)" : "\(_num)/\(_den)"}
}
init(_num:Int,_den:Int){
self._num = _num
self._den = _den
pan()
simplify()
}
func add(other:Fraction) -> Fraction {
return Fraction(_num: _num * other._den + other._num * _den, _den: _den * other._den)
}
func sub(other:Fraction) -> Fraction {
return Fraction(_num: _num * other._den - other._num * _den, _den: _den * other._den)
}
func mul(other:Fraction) -> Fraction {
return Fraction(_num: _num * other._num , _den: _den * other._den)
}
func div(other:Fraction) -> Fraction {
return Fraction(_num: _num * other._den, _den: _den * other._num)
}
func simplify() -> Fraction{
if _num == 0 {
_den = 1
}
else {
let x = abs(_num)
let y = abs(_den)
let g = gcd(x, y)
_num /= g
_den /= g
}
return self
}
func pan() -> Fraction{
if _den < 0{
_num = -_num
_den = -_den
}
return self
}
}
// 运算符重载 - 为自定义的类型定义运算符
func +(one:Fraction,two:Fraction ) -> Fraction{
return one.add(two)
}
func -(one:Fraction,two:Fraction ) -> Fraction{
return one.sub(two)
}
func *(one:Fraction,two:Fraction ) -> Fraction{
return one.mul(two)
}
func /(one:Fraction,two:Fraction ) -> Fraction{
return one.div(two)
}
类的外部实现:
let f1 = Fraction(_num: 3, _den: -4)
let f2 = Fraction(_num: 8, _den: 9)
print(f1.info)
print(f2.info)
let f3 = f1 + f2
print(f3.info)
let f4 = f1 - f2
print(f4.info)
let f5 = f1 * f2
print(f5.info)
let f6 = f1 / f2
print(f6.info)
运行结果:
-3/4
8/9
5/36
-59/36
-2/3
-27/32
运算符重载
func <(one:Student,two:Student) -> Bool{
return one.age < two.age
}
let stuArray = [
Student(name: "张小凡 ", age: 60),
Student(name: "陆雪琪", age: 50),
Student(name: "碧瑶", age: 40),
Student(name: "小灰", age: 30)]
// 运算符 重载法
let newArray = stuArray.sort(<)
for stu in newArray{
print("\(stu.name):\(stu.age)")
}
//尾随闭包法
let new = stuArray.sort {$0.name < $1.name}
for stu in new{
print("\(stu.name):\(stu.age)")
}
运行结果
小灰:30
碧瑶:40
陆雪琪:50
张小凡 :60
小灰:30
张小凡 :60
碧瑶:40
陆雪琪:50
扑克游戏
先定义一张牌的类
enum Suite:String{
case Spade = "️",Heart = "️",Club = "️",Diamond = "️"
}
/// 一张牌
class Card{
var suite:Suite
var face:Int
init(suite:Suite,face:Int){
self.suite = suite
self.face = face
}
var info:String{
get{
var str:String
str = suite.rawValue
switch face {
case 1:str += "A"
case 11:str += "J"
case 12:str += "Q"
case 13:str += "K"
default:str += "\(face)"
}
return str
}
}
}
再定义一副牌的类:
func randomIn(min:UInt32,_ max:UInt32) -> Int{
return Int(arc4random_uniform(max - min + 1) + min)
}
/// 一副牌
class Poker{
var cardsArray:[Card]
init(){
cardsArray = []
reset()
}
///重置所有的牌
func reset(){
cardsArray.removeAll()
let suites = [Suite.Spade,.Heart,.Club,.Diamond]
for suite in suites {
for face in 1...13{
let card = Card(suite: suite, face: face)
cardsArray.append(card)
}
}
}
///洗牌
func shuffle(){
// 洗牌前嫌重置所有的牌
reset()
//通过随机乱序的方法 交换牌的位置达到洗牌目的
for i in 0..<cardsArray.count{
let j = randomIn(0, UInt32(cardsArray.count - 1))
(cardsArray[i],cardsArray[j]) = (cardsArray[j],cardsArray[i])
}
}
///发牌
func deal() -> Card?{
if hasMoreCards{
return cardsArray.removeLast()
}
return nil
}
///判断还有没有牌可以发
var hasMoreCards:Bool{
get{return cardsArray.count > 0}
}
}
定义一个玩家类:
func <(one:Card,two:Card) -> Bool{
return one.face < two.face
}
class Player {
var nickname:String
var cardsOnHand:[Card] = []
var isGetCard = true
init(nickname:String){
self.nickname = nickname
}
func getOneCard(card:Card){
cardsOnHand.append(card)
}
func Cnumber() -> Int{
var n:Int = 0
for card in cardsOnHand{
n += card.face
}
return n
}
func sortCards(){
cardsOnHand.sortInPlace(<)
}
func showPlayerCards(){
print("\(nickname):",terminator:"")
for card in cardsOnHand{
print(card.info,terminator:" ")
}
}
}
类外主函数实现:
let p = Poker()
p.shuffle()
let playerArray = [
Player(nickname: "张小凡"),
Player(nickname: "陆雪琪"),
Player(nickname: "碧瑶"),
Player(nickname: "小灰")]
for _ in 1...3{
for player in playerArray{
if p.hasMoreCards{
player.getOneCard(p.deal()!)
}
}
}
for player in playerArray{
player.sortCards()
player.showPlayerCards()
print("")
print("")
}
运行结果:
张小凡: 3 ️4 ️J
陆雪琪:️4 ️5 ️6
碧瑶:️4 ️5 ️Q
小灰:️7 ️10 ️K
继承
继承我们可以理解为一个类获取了另外一个类的方法和属性。
当一个类继承其它类时,继承类叫子类,被继承类叫超类(或父类)
我们可以将子类型的对象赋值给父类型的变量(因为子类型跟父类型之间是IS-A关系)
实例:先定义一个基类Person
enum Gender{
case Male
case Female
}
class Person{
var name: String
var age: Int
var gender:Gender
init(name:String,age:Int,gender:Gender){
self.name = name
self.age = age
self.gender = gender
}
func eat(food:String){
print("\(name)正在吃\(food)")
}
}
子类:创建一个属于Person类的学生子类Stu
class Stu:Person {
var major:String
init(name: String, age: Int, gender: Gender,major:String) {
self.major = major
super.init(name: name, age: age, gender: gender)
}
func study(courseName:String) -> Bool{
print("\(name)正在学习\(courseName)")
return true
}
}
再创建一个属于Person类的老师子类Teacher类:
class Teacher:Person {
var title:String
init(name: String, age: Int, gender: Gender,title:String) {
self.title = title
super.init(name: name, age: age, gender: gender)
}
func teach (couresName:String){
print("\(name)\(title)正在教\(couresName).")
}
}
创建类的对象:
let p1 = Person(name: "雄大", age: 40, gender: .Female)
p1.eat("面包")
let p2:Person = Stu(name: "熊二", age: 35,gender:.Male ,major:"学生")
p2.eat("西瓜")
运行结果:
雄大正在吃面包
熊二正在吃西瓜
如果要将父类型的变量转化成子类型需要用as运算符进行类型转换
如果能够确认父类型的变量中就是某种子类型的对象可以用as!进行转换
如果不确定父类型的变量中是哪种子类型,可以用as?尝试转换
(p2 as! Stu).study("swift")
if let temp = p2 as? Teacher {
temp.teach("Java")
}
else{
print("\(p2.name)不是老师!!")
}
let p3 = Teacher(name: "熊三", age: 35, gender: .Male, title: "教授")
p3.eat("黄瓜")
p3.teach("IOS")
运行结果:
熊二正在学习swift
熊二不是老师!!
熊三正在吃黄瓜
熊三教授正在教IOS.
多态
多态(polymorphism) - 同样的对象类型(Pet类型)调用相同的方法,做了不同的事情
父类有的方法子类可以重新实现,这个过程叫方法重写
需要在方法前添加 override 关键字
重写有时也被称为:置换,覆写
实现多态的关键步骤:
1.子类在继承父类的过程中,对父类已有的方法进行重写,不同的子类有各自不同的重写
2.对象造型(将子类对象当成父类型来使用)
创建宠物
首先创建一个宠物类
class Pet{
var nickName:String
var gender:Gender
var age:Int
init(nickName:String,gender:Gender,age:Int){
self.nickName = nickName
self.gender = gender
self.age = age
}
func play(){
print("\(nickName)正在玩耍")
}
func eat(){
print("\(nickName)正在吃东西")
}
func shout(){
print("\(nickName)发出叫声")
}
}
定义一个猫类 - 属于 Pet 类
class Cat: Pet {
var hairColor:String
init(nickName: String, gender: Gender, age: Int,hairColor:String) {
self.hairColor = hairColor
super.init(nickName: nickName, gender: gender, age: age)
}
override func play() {
super.play()
print("\(nickName)正在玩毛线球")
}
override func shout() {
print("\(nickName):喵喵喵...")
}
func catchMouce(){
print("\(nickName)正在抓")
}
}
定义一个狗类
class Dog: Pet {
var isLarge:Bool
init(nickName: String, gender: Gender, age: Int,isLarge:Bool) {
self.isLarge = isLarge
super.init(nickName: nickName, gender: gender, age: age)
}
override func play() {
super.play()
print("\(nickName)正在玩皮球!!")
}
override func shout() {
print("\(nickName):汪汪汪汪...")
}
func porter(){
if isLarge{
print("\(nickName)正在看门!!!")
}
else{
print("\(nickName)太小了谁也打不过!!!")
}
}
}
类外函数实现:
let petsArray = [
Cat(nickName: "汤姆猫", gender: .Female, age: 5, hairColor: "黄色"),
Dog(nickName: "大黄", gender: .Female, age: 4, isLarge: true),
Dog(nickName: "小灰", gender: .Male, age: 3, isLarge: false)]
for pet in petsArray{
pet.shout()
if let dog = pet as? Dog {
dog.porter()
}
else if let cat = pet as? Cat {
cat.catchMouce()
}
}
运行结果:
汤姆猫:喵喵喵...
汤姆猫正在抓
大黄:汪汪汪汪...
大黄正在看门!!!
小灰:汪汪汪汪...
小灰太小了谁也打不过!!!
我们再创建一个人类来领养宠物:
class Pers {
var name:String
var pet:Pet? // 人跟宠物之间是HAS-A关系(关联)
init(name:String){
self.name = name
}
func adopt(pet:Pet){
print("\(name)领养了\(pet.nickName)")
self.pet = pet
}
func strike(){
if let pet = pet {
print("\(name)正在打\(pet.nickName)")
pet.shout()
}
else{
print("\(name)正在自虐!!!")
}
}
func play(){
if let pet = pet{
print("\(name)正在和\(pet.nickName)玩耍")
}
else{
print("\(name)正在自嗨!!!")
}
}
}
Pers人类的调用:
let person = Pers(name: "雄大")
let dog = Dog(nickName: "大黄", gender: .Female, age: 1, isLarge: true)
let cat = Cat(nickName: "汤姆猫", gender: .Male, age: 1, hairColor: "黄色")
person.adopt(cat)
dog.play()
person.strike()
运行结果:
雄大领养了汤姆猫
雄大正在打汤姆猫
汤姆猫:喵喵喵...
科普小知识:
面向对象的7原则:
- 1.单一职责原则(SRP)
- 2.开闭原则(OCP)
- 3.接口隔离原则
- 4.合成聚合复用原则
- 5.迪米特法则
- 6.依赖倒转原则(面向抽象编程,DIP)
- 定义方法参数类型的时候尽可能使用父类型(抽象类型)
- 因为如果用父类型的参数调用方法时可以传入任意的子类型对象
- 7.里式替换原则(LSP) - 能用父类型的地方就一定可以使用子类型
- (想要更详细的了解,可以百度下)
2.jpg
总结
这一周的知识点及代码量远非第一周可比,内容更加的高深,但正如我刚开始所说,因为专注,所以时间飞逝。知识在于自己学,方法在于自己用,当你用你所学做你想做后,自然而然就会投入,那么时间就要飞了...
————愿时光匆匆,我只在乎你....