1. 第一天
字典和集合(由于他们在内存中不是有序排序的,所以打印他们元素时时不规则显示的)
// 哈希码(hash code)/散列码
// MD5 / SHA-1
1.1 字典 var dict: [String: String]
// 字典(存放键值对组合的容器)
// 字典中的每个元素都是由两部分构成的, 冒号前面是键,冒号后面是值
var dict: [String: String] = ["abacus": "算盘", "abnormal": "异常的", "hello" : "你好", "good": "好的"]
// 通过键获取对应的值(可空类型, 因为给的键有可能没有与之对应的值)
// key ---> value
print(dict["hello"]!)
print(dict["abcxyz"]) // 返回nil
// 添加元素
dict["shit"] = "狗屎"
dict["delicious"] = "好吃的"
print(dict)
// 删除元素
// dict.removeValueForKey("hello")
dict["hello"] = nil
print(dict)
print(dict["hello"])
// 修改元素
dict["shit"] = "牛粪"
print(dict)
// 遍历字典中所有的值
for value in dict.values {
print(value)
}
// 遍历字典中所有的键
for key in dict.keys {
print("\(key) ---> \(dict[key])")
}
// 直接通过一个元组获得字典中的键和值(原始类型)
for (key, value) in dict {
print("\(key) ---> \(value)")
}
1.2 集合 var a: Set
var a: Set = [1, 2, 3, 1, 2, 5]
a.insert(100) // 添加元素
a.remove(2) // 删除元素
print(a)
var b: Set = [3, 5, 7, 9, 11]
print(b)
print(a.intersect(b)) // 交集(a和b都有的元素)
print(a.union(b)) // 并集(a和b的所有元素)
print(a.subtract(b)) // 差集(a有b没有的元素)
print(a == b)
print(b.isSubsetOf(a))
let c: Set = [1, 3]
print(c.isSubsetOf(a)) // 判断c是不是a的子集
print(a.isSupersetOf(c)) // 判断a是不是c的超集
let d: Set = [2, 1000, 10000]
print(a.isDisjointWith(d)) // 判断两个集合是否相交
1.3 函数
** inout - 输入输出参数(不仅将数据传入函数还要从函数中取出数据)
Swift中函数的参数列表可以是可变参数列表(参数的个数是任意多个)
Swift中函数的参数可以设定默认值,如果调用函数的时候没有给该参数赋值就直接使用默认值
可以使用元组(tuple)让函数一次返回多条数据**
// 函数的参数名
// 函数名(外部参数名 内部参数名: 类型, 外部参数名 内部参数名: 类型)
// 如果不写外部参数名那么内部参数名也是外部参数名
// 可以使用_来作为外部参数名表示省略外部参数名
func myMin(a x: Int, b y: Int) -> Int {
return x < y ? x : y
}
// 调用函数的时候要写函数的外部参数名
print(myMin(a: 3, b: 5))
// 定义函数
// func 函数名(参数列表) -> 返回类型 { 函数的执行体 }
// Swift中函数的参数可以设定默认值
// 如果调用函数的时候没有给该参数赋值就直接使用默认值
func sayHello(personName: String, alreadyGreeted: Bool = false) -> String {
// let greeting = "Hello, " + personName + "!"
// 如果函数的返回类型不是Void 那么函数中一定有return语句
// return greeting
// personName = "王小锤" // 编译错误
if alreadyGreeted {
return "怎么又是你, " + personName + "!"
}
else {
return "你好, " + personName + "!"
}
}
// 调用函数
// 函数名(参数值)
// 调用Swift的函数时, 在默认情况下从第二个参数开始需要写参数名
print(sayHello("王大锤", alreadyGreeted: true))
// 如果没有给第二个参数赋值那么就直接使用默认值false
let str = sayHello("Jack")
print(str)
// Swift中函数的参数列表可以是可变参数列表(参数的个数是任意多个)
func sum(nums: Int...) -> Int {
var total = 0
for num in nums {
total += num
}
return total
}
print(sum())
print(sum(999))
print(sum(1, 2, 3))
print(sum(90, 82, 37, 68, 55, 11, 99))
// 可以使用元组(tuple)让函数一次返回多条数据
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.count == 0 {
return nil
}
var currentMin = array[0]
var currentMax = array[0]
for value in array[1.. currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let b = minMax([23, 45, 99, 68, 72, 12, 55]) {
print(b.min) // print(b.0)
print(b.max) // print(b.1)
}
else {
print("数组中没有元素!!!")
}
func swap(inout a: Int, inout _ b: Int) -> Void {
(a, b) = (b, a)
// let temp = a
// a = b
// b = temp
}
var a = 300, b = 500
swap(&a, &b)
print("a = \(a)")
print("b = \(b)")
// inout - 输入输出参数(不仅将数据传入函数还要从函数中取出数据)
func createX(inout x: Int) {
x = 1000
}
var x = 1
// inout类型的参数前要加上&符号
createX(&x)
print(x)
//var x = 5, y = 10
//// 函数调用传参都是传值
//swap(x, y)
//print("x = \(x)")
//print("y = \(y)")
1.4 练习
1.4.1 设计一个函数根据系统时间返回不同的问候语
func sayHello(name: String) -> String {
let date = NSDate()
let cal = NSCalendar.currentCalendar()
let hour = cal.component(.Hour, fromDate: date)
var greeting: String
switch hour {
case 0...6: // 不同的分支可以有重叠的部分
greeting = "怎么还没睡呀"
// fallthrough // 无条件继续执行下一个case
case 4...10: // 匹配了一个分支之后不再匹配其他的分支
greeting = "早起的鸟儿有虫吃"
case 11...13:
greeting = "中午好"
case 14...18:
greeting = "下午好"
default:
greeting = "晚上好"
}
return name + ", " + greeting + "!"
}
print(sayHello("刘备"))
在这里主要强调的是如何当前获取时间
let date = NSDate()
let cal = NSCalendar.currentCalendar()
let hour = cal.component(.Hour, fromDate: date)
1.4 指纹支付代码
import UIKit
import LocalAuthentication
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let errPointer = NSErrorPointer()
let ctx = LAContext()
// 判断设备是否支持指纹识别
if ctx.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, error: errPointer) {
// z = f(x, g(y))
// Swift中允许将一个函数作为另一个函数的参数
// evalutePolicy方法的第三个参数是一个函数
// 该函数有两个参数没有返回值
// 给该参数传参时可以在花括号中写一个匿名函数传进去
// 该匿名函数通常也称之为闭包(closure)
ctx.evaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "请输入指纹进行支付", reply: { (isOK, err) -> Void in
if isOK {
print("支付成功!!!")
}
else {
print("指纹验证失败, 请输入支付密码")
}
})
}
else {
print("你的设备不支持指纹识别")
}
}
}
1.4 设计一个函数,传入年月日,返回该日期是这一年的第几天
func isLeapYear(year: Int) -> Bool {
return year % 4 == 0 && year % 100 != 0 || year % 400 == 0
}
func daysOfYear(year: Int, _ month: Int, _ day: Int) -> Int {
let daysOfMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
// if isLeapYear(year) {
// daysOfMonth[1] = 29
// }
var sum = 0
// for days in daysOfMonth[0.. 2 {
sum += 1
}
return sum + day
// var num = 0
// for i in 1..
1.4 函数的递归调用(一个函数直接或间接的调用自身)
// 1. 递归公式
// 2. 收敛条件
// 用递归计算1~n的和
func sum(n: Int) -> Int {
if n == 1 {
return 1
}
return n + sum (n - 1)
}
print(sum(100))
// 汉诺伊塔
var counter = 1
func hanoi(n: Int, _ a: String, _ b: String, _ c: String) {
if n > 0 {
hanoi(n - 1, a, c, b)
print("\(counter): \(a)--->\(b)")
counter += 1
hanoi(n - 1, c, b, a)
}
}
hanoi(1, "A", "B", "C")
counter = 1
hanoi(2, "A", "B", "C")
counter = 1
hanoi(5, "A", "B", "C")
2. 第二天
2.1 函数的扩展
func sum(a: Int, _ b: Int) -> Int {
return a + b
}
func mul(a: Int, _ b: Int) -> Int {
return a * b
}
// 在Swift中函数是一种类型
// 这也就意味着函数可以作为变量或常量的类型
// 同理函数也可以作为另一个函数的参数或返回值
func foo(array: [Int], fn: (Int, Int) -> Int) -> Int {
var sum = array[0]
for x in array[1.. Int类型的函数
print(foo(a, fn: sum))
// 2. 传入已有的二元运算符: +-*/%(因为运算符也是函数)
print(foo(a, fn: +))
// 3. 传入匿名函数(闭包)
// 3.1 完整的闭包写法
print(foo(a, fn: { (a, b) -> Int in
return a + b
}))
// 3.2 省略掉类型和不必要的括号
print(foo(a, fn: { a, b in a + b }))
// 3.3 省略参数名
print(foo(a, fn: { $0 + $1 }))
// 3.4 尾随闭包
print(foo(a) { (a, b) -> Int in
return a + b
})
print(foo(a) { $0 + $1 })
var array = ["game", "abacus", "hello", "cat", "good", "internationalization", "chaos", "dislike", "zealot", "young"]
// array.sortInPlace(>)
array.sortInPlace({ $0 > $1 })
// array.sortInPlace() { $0 > $1 }
// array.sortInPlace { $0 > $1 }
// 如果函数的最后一个参数是闭包可以写成尾随闭包的形式
// 也就是将闭包放到函数参数的圆括号外面写在一对花括号中
// 如果函数后面有尾随闭包且函数的圆括号中没有参数
// 那么函数的圆括号也可以省略(仅限于有尾随闭包的场景)
array.sortInPlace {
if $0.characters.count == $1.characters.count {
return $0 < $1
}
return $0.characters.count < $1.characters.count
}
print(array)
2.2 数组的三个重要方法:过滤、映射、缩减
let array = [23, 37, 96, 55, 40, 92, 68, 88]
// 1. 过滤
let newArray1 = array.filter { $0 > 50 }
print(newArray1)
let newArray2 = array.filter { $0 % 2 == 0 }
print(newArray2)
// 2. 映射
let newArray3 = array.map { $0 * $0 }
print(newArray3)
let newArray4 = array.map { sqrt(Double($0)) }
print(newArray4)
// 3. 缩减
let result1 = array.reduce(0, combine: +)
print(result1)
let result2 = array.reduce(1, combine: *)
print(result2)
let result3 = array.reduce(array[0]) {
$1 > $0 ? $1 : $0
}
print(result3)
let strArray = ["I", "love", "you"]
let result4 = strArray.reduce("") { $0 + " " + $1 }
print(result4)
2.3 类
2.3.1 定义类
// 步骤1: 定义类(如果你要用的类苹果已经提供了就直接进入第2步)
// 定义类就可以创建出新的类型
// 学生类
class Student {
// 变量定义到类的外面就叫变量 - variable
// 变量定义到类的里面就叫属性 - property
// 数据抽象 - 找到和学生相关的属性(找名词)
var name: String
var age: Int
// 初始化方法(构造方法/构造器) - constructor
init(name: String, age: Int) {
self.name = name
self.age = age
}
// 函数写到类的外面就叫函数 - function
// 函数写到类的里面就叫方法 - method
// 行为抽象 - 找到和学生相关的方法(找动词)
func eat() {
print("\(name)正在吃饭.")
}
func study(courseName: String) {
print("\(name)正在学习\(courseName).")
}
func watchJapaneseAV() {
if age >= 18 {
print("\(name)正在观看动作片.")
}
else {
print("亲爱的\(name), 我们推荐你观看《熊出没》")
}
}
}
// 步骤2: 创建对象(调用初始化方法)
let stu1 = Student(name: "刘备", age: 35)
// 步骤3: 给对象发消息(通过给对象发消息来解决问题)
stu1.eat()
stu1.study("Swift程序设计")
stu1.watchJapaneseAV()
let stu2 = Student(name: "王大锤", age: 15)
stu2.eat()
stu2.study("中国近代史")
stu2.watchJapaneseAV()
// 0. 发现类
// - 在对问题的描述中找名词和动词
// - 名词会成为类或者类中的属性 动词会成为类中的方法
// 1. 定义类
// - 数据抽象(属性)
// - 行为抽象(方法)
// - 初始化方法
// 访问修饰符
// - public (公开)
// - internal (内部的) - 默认
// - private (私有)
class Circle {
// stored property
// 存储属性(保存和圆相关的数据的属性)
var center: Point
var radius: Double
init(center: Point, radius: Double) {
self.center = center
self.radius = radius
}
// 通常获得某个计算出的值的方法都可以设计成计算属性
// computational property
// 计算属性(通过对存储属性做运算得到的属性)
var perimeter: Double {
// 圆的周长是一个只读属性
// 所以此处只有get{}没有set{}
get { return 2 * M_PI * radius }
}
var area: Double {
get { return M_PI * radius * radius }
}
}
2.3.1 定义一个走动的时钟类
class Clock {
var hour: Int
var minute: Int
var second: Int
init() {
let date = NSDate()
let cal = NSCalendar.currentCalendar()
hour = cal.component(.Hour, fromDate: date)
minute = cal.component(.Minute, fromDate: date)
second = cal.component(.Second, fromDate: date)
}
func showTime() -> String {
return "\(hour):\(minute):\(second)"
}
func run() {
second += 1
if second == 60 {
second = 0
minute += 1
if minute == 60 {
minute = 0
hour += 1
if hour == 24 {
hour = 0
}
}
}
}
}
let clock = Clock()
while true {
print(clock.showTime())
sleep(1)
clock.run()
}
3. 第三天
3.1 函数的扩展2
3.1.1 convenience调用其他的初始化方法
我们可以在一个类中定义多个初始化方法
利用convenience调用其他的初始化方法来初始化方法
class Point {
var x: Double
var y: Double
// 我们可以在一个类中定义多个初始化方法
// 便利初始化方法 / 便利构造器
// 利用convenience调用了其他的初始化方法的初始化方法
convenience init() {
self.init(x: 0, y: 0)
}
convenience init(point: (Double, Double)) {
self.init(x: point.0, y: point.1)
}
// 指派初始化方法 / 指派构造器
// 被其他初始化方法调用的初始化方法
init(x: Double, y: Double) {
self.x = x
self.y = y
}
func distanceTo(other: Point) -> Double {
let dx = x - other.x
let dy = y - other.y
return sqrt(dx * dx + dy * dy)
}
func moveTo(x: Double, _ y: Double) {
self.x = x
self.y = y
}
func moveBy(dx: Double, _ dy: Double) {
x += dx
y += dy
}
}
3.1.2 类扩展(extension)
如果在某个特定的应用场景中你发现现有的类缺少了某项功能
那么可以通过类扩展(extension)的方式现场添加这项功能
// 如果color为nil就取??后面的值
// 如果color不为nil就直接使用color的值
(color ?? UIColor.blueColor()).set()
// 如果在某个特定的应用场景中你发现现有的类缺少了某项功能
// 那么可以通过类扩展(extension)的方式现场添加这项功能
extension Point {
var cgPoint: CGPoint {
get { return CGPointMake(CGFloat(x), CGFloat(y)) }
}
}
func randomInt(min: UInt32, _ max: UInt32) -> Int {
return Int(arc4random_uniform(max - min + 1) + min)
}
extension CGPoint {
var myPoint: Point {
get {
return Point(x: Double(self.x), y: Double(self.y))
}
}
}
class Triangle {
var va: Point
var vb: Point
var vc: Point
var color: UIColor?
init(va: Point, vb: Point, vc: Point) {
self.va = va
self.vb = vb
self.vc = vc
}
var perimeter: Double {
get {
let ab = va.distanceTo(vb)
let bc = vb.distanceTo(vc)
let ca = vc.distanceTo(va)
return ab + bc + ca
}
}
var area: Double {
get {
let ab = va.distanceTo(vb)
let bc = vb.distanceTo(vc)
let ca = vc.distanceTo(va)
let halfP = perimeter / 2
return sqrt(halfP * (halfP - ab) * (halfP - bc) * (halfP - ca))
}
}
func draw() {
let bezierPath = UIBezierPath()
bezierPath.moveToPoint(va.cgPoint)
bezierPath.addLineToPoint(vb.cgPoint)
bezierPath.addLineToPoint(vc.cgPoint)
bezierPath.addLineToPoint(va.cgPoint)
// bezierPath.closePath()
// bezierPath.fill()
// 如果color为nil就取??后面的值
// 如果color不为nil就直接使用color的值
(color ?? UIColor.blueColor()).set()
bezierPath.fill()
}
}
var circleArray: [Circle] = []
override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
if let touch = touches.first {
let touchPoint = touch.locationInView(self)
let c = Circle(center: touchPoint.myPoint, radius: Double(randomInt(150, 250)))
circleArray.append(c)
setNeedsDisplay()
}
}
3.1.3 newValue为设置的值
var hp: Int {
get { return _hp }
set { _hp = newValue > 0 ? newValue : 0 }
}
3.2 奥特曼打小怪兽
// 奥特曼类
func randomInt(min: UInt32, _ max: UInt32) -> Int {
return Int(arc4random_uniform(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
}
}
var hp: Int {
get {
return _hp
}
set {
_hp = newValue > 0 ? newValue : 0
}
}
init(name: String, hp: Int, mp: Int) {
_name = name
_hp = hp
_mp = mp
}
func attack(monster: Monster) {
let injury = randomInt(15, 20)
monster.hp -= injury
_mp = _mp + 5 > 100 ? 100 : _mp + 5
}
func hugeAttack(monster: Monster) {
let injury = monster.hp * 3 / 4 >= 50 ? monster.hp * 3 / 4 : 50
monster.hp -= injury
}
func magicalAttack(monster: [Monster]) -> Bool {
if _mp >= 30 {
for monster in monster {
if monster.isAlive {
let injury = randomInt(5, 15)
monster.hp -= injury
}
}
_mp -= 30
return true
}
return false
}
}
// 小怪兽类
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
_hp = hp
}
func attack(ultraman: UItraman) {
let injury = randomInt(5, 10)
ultraman.hp -= injury
}
}
// 主方法调用
// 奥特曼打小怪兽
// 从一群小怪兽中挑选一只活着的小怪兽
func pickOneMonster(mArray: [Monster]) -> Monster {
var monster: Monster
repeat {
let randomIndex = randomInt(0, UInt32(mArray.count - 1))
monster = mArray[randomIndex]
} while !monster.isAlive
return monster
}
// 判断小怪兽是否全部死光
func isAllDead(mArray: [Monster]) -> Bool {
for monster in mArray {
if monster.isAlive {
return false
}
}
return true
}
let u = UItraman(name: "迪迦", hp: 300, mp: 80)
let mArray = [
Monster(name: "熊丹凌", hp: 120),
Monster(name: "欧阳坚", hp: 250),
Monster(name: "张尼玛", hp: 180),
Monster(name: "王尼玛", hp: 150)
]
var round = 1
repeat {
print("======第\(round)回合=======")
let m = pickOneMonster(mArray)
let factor = randomInt(1, 10)
switch factor {
case 1...7:
print("\(u.name)奥特曼使用了普通攻击")
u.attack(m)
if m.isAlive {
m.attack(u)
}
case 8...9:
if u.magicalAttack(mArray) {
for m in mArray {
if m.isAlive {
m.attack(u)
}
}
print("\(u.name)奥特曼使用了吞天噬地")
}
else {
u.attack(m)
if m.isAlive {
m.attack(u)
}
print("\(u.name)奥特曼使用了普通攻击")
}
default:
print("\(u.name)奥特曼使用了动感光波")
u.hugeAttack(m)
}
u.attack(m)
if m.isAlive {
m.attack(u)
}
print("\(u.name)奥特曼生命值:\(u.hp)")
print("\(u.name)奥特曼魔法值:\(u.mp)")
for m in mArray {
print("\(m.name)小怪兽生命值:\(m.hp)")
}
round += 1
} while u.isAlive && !isAllDead(mArray)
if u.hp > 0 {
print("\(u.name)奥特曼获胜")
}
else {
print("小怪兽获胜")
}
4. 第四天
4.1 学生姓名隐去最后一个字符,学写文档
_name.characters.count获得字符串长度
_name.substringToIndex(_name.endIndex.predecessor())去掉最后一个字
/// 学生姓名隐去最后一个字符
public var name: String {
get {
let displayName = _name.substringToIndex(_name.endIndex.advancedBy(-1))
return displayName + "*"
}
}
public var name: String {
get {
let value = _name.characters.count > 2 ? -2 : -1
//let displayName = _name.substringToIndex(_name.endIndex.predecessor())
//let displayName = _name.substringToIndex(_name.endIndex.advancedBy(-1))
let displayName = _name.substringToIndex(_name.endIndex.advancedBy(value))
return displayName + "*"
}
}
/**
学习
- parameter courseName: 课程的名称
- parameter hour: 学习时间
- returns: 学会了返回true否则返回false
*/
public func study(courseName: String, hour: Int) -> Bool {
print("\(_name)正在学习\(courseName).")
return hour > 180 ? true : false
}
4.2 短除法(欧几里得算法)
// 短除法(欧几里得算法)
// x和y的最大公约数跟y%x和x的最大公约数是一样的
// Greatest Common Divisor
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
}
}
// 主方法调用
4.3 写一个使用分数进行运算的类
// 短除法(欧几里得算法)
// x和y的最大公约数跟y%x和x的最大公约数是一样的
// Greatest Common Divisor
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) {
_num = num
_den = den
simplify()
normalize()
}
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 normalize() -> Fraction {
if _den < 0 {
_num = -_num
_den = -_den
}
return self
}
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 +(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.add(f2)
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 模拟扑克游戏
Card类
enum Direction: Int {
case Up, Right, Down, Left
}
// GET: 枚举是定义符号常量的最佳方式
// GET: 符号常量总是优于字面常量
/**
花色的枚举
- Spade: 黑桃
- Heart: 红心
- Club: 草花
- Diamond: 方块
*/
enum Suite: String {
case Spade = "♠️"
case Heart = "❤️"
case Club = "♣️"
case Diamond = "♦️"
}
/// 一张牌
class Card {
var suite: Suite
var face: Int
/**
初始化方法
- parameter suite: 花色
- parameter face: 点数
*/
init(suite: Suite, face: Int) {
self.suite = suite
self.face = face
}
/// 牌的信息
var info: String {
get {
var 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
}
}
}
Poker类
func randomInt(min: UInt32, _ max: UInt32) -> Int {
return Int(arc4random_uniform(max - min + 1) + min)
}
/// 一副牌
class Poker {
var cardsArray: [Card] = []
init() {
reset()
}
/**
重置所有的牌
*/
func reset() {
// 移除数组中剩下的牌
cardsArray.removeAll()
// 将52张牌按照黑红梅方的顺序放到数组中
let suitesArray = [Suite.Spade, .Heart, .Club, .Diamond]
for suite in suitesArray {
for face in 1...13 {
let card = Card(suite: suite, face: face)
cardsArray.append(card)
}
}
}
/**
洗牌
*/
func shuffle() {
// 洗牌之前先重置所有的牌
reset()
// 通过随机乱序的方式打乱牌的位置
for i in 0.. Card? {
if hasMoreCards {
return cardsArray.removeFirst()
}
return nil
}
/// 还有没有更多的牌
var hasMoreCards: Bool {
get { return cardsArray.count > 0 }
}
}
Player类
func <(one: Card, two: Card) -> Bool {
return one.face < two.face
}
class Player {
var nickname: String
var cardsOnHand: [Card] = []
init(nickname: String) {
self.nickname = nickname
}
func getOneCard(card: Card) {
cardsOnHand.append(card)
}
func sortCards() {
cardsOnHand.sortInPlace(<)
}
}
主方法调用
func showPlayerCards(player: Player) {
print("\(player.nickname)", terminator: ": ")
player.sortCards()
for card in player.cardsOnHand {
print(card.info, terminator: " ")
}
print("")
}
// 扑克游戏
let p = Poker()
p.shuffle()
let playersArray = [
Player(nickname: "张尼玛"),
Player(nickname: "王尼玛"),
Player(nickname: "李尼玛"),
Player(nickname: "刘尼玛")
]
for _ in 1...3 {
for player in playersArray {
if p.hasMoreCards {
player.getOneCard(p.deal()!)
}
}
}
for player in playersArray {
showPlayerCards(player)
}
5. 第五天 继承和多态
5.1 继承
// 继承: 从已有的类创建新类的过程
// 提供继承信息的称为父类(超类/基类)
// 得到继承信息的称为子类(派生类/衍生类)
// 通常子类除了得到父类的继承信息还会增加一些自己特有的东西
// 所以子类的能力一定比父类更强大
// 继承的意义在于子类可以复用父类的代码并且增强系统现有的功能
子类继承父类时,增加了自己属性时,若需初始化方法,需先给自己赋值,再调用父类;若没增加属性,要初始化方法,需重写初始化方法用override
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() {
print("\(name)正在吃饭.")
}
}
// 老师类继承Person类
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(courseName: String) {
print("\(name)\(title)正在教\(courseName).")
}
}
主方法调用
let p1 = Person(name: "王大锤", age: 25, gender: .Male)
p1.eat()
// 可以将子类型的对象赋值给父类型的变量(因为子类跟父类之间是IS-A关系)
// Person和Pet之间是HAS-A(关联)
// 学生是人, 老师是人, 所以学生和老师的对象可以赋值给人类型的变量
let p2: Person = Student(name: "张尼玛", age: 18, gender: .Female, major: "计算机科学与技术")
p2.eat()
// 如果要将父类型的变量转换成子类型需要用as运算符进行类型转换
// 如果能够确认父类型的变量中就是某种子类型的对象可以用as!进行转换
// 如果不确定父类型的变量中是哪种子类型可以用as?尝试转换
(p2 as! Student).study("Swift程序设计")
if let temp = p2 as? Teacher {
temp.teach("Java")
}
else {
print("\(p2.name)不是老师!!!")
}
let p3: Person = Teacher(name: "骆昊", age: 35, gender: .Male, title: "叫兽")
p3.eat()
// p3.teach("HTML网页设计")
// 终极原则: 高内聚, 低耦合
// 面向对象七原则:
// 1. 单一职责原则(SRP)
// 2. 开闭原则(OCP)
// 3. 依赖倒转原则(面向抽象编程, DIP)
// 爱人, 待周爱人而后为爱人
// 《墨子·取周》
// 定义方法参数类型的时候尽可能使用父类型(抽象类型)
// 因为如果用父类型的参数调用方法时可以传入任意子类型对象
// 4. 里氏替换原则(LSP) - 能用父类型的地方就一定可以使用子类型
// 白马, 马也, 乘白马, 乘马也
// 黑马, 马也, 乘黑马, 乘马也
// 娣, 美人也, 爱娣非爱美人也
// 盗, 人也, 恶盗非恶人也
// 《墨子·小取》
// 5. 接口隔离原则(ISP)
// 6. 合成聚合复用原则(CARP)
// 7. 迪米特法则(LoD)
// GoF(四人帮)设计模式 - 23种设计模式
var name: String
var pet: Pet? // Person和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)正在自虐.")
}
}
5.2 多态
// 同样的对象类型(Pet类型)接收相同的消息(调用相同的方法)
// 但是做了不同的事情 这就是多态(polymorphism)
// 实现多态的关键步骤:
// 1. 方法重写(子类在继承父类的过程中对父类已有的方法进行重写, 而且不同的子类给出各自不同的实现版本)
// 2. 对象造型(将子类对象当成父类型来使用)
for pet in petsArray {
pet.eat()
pet.play()
// 同样的对象类型(Pet类型)接收相同的消息(调用相同的方法)
// 但是做了不同的事情 这就是多态(polymorphism)
// 实现多态的关键步骤:
// 1. 方法重写(子类在继承父类的过程中对父类已有的方法进行重写, 而且不同的子类给出各自不同的实现版本)
// 2. 对象造型(将子类对象当成父类型来使用)
pet.shout()
// 可以通过if+as?将父类型安全的转换成子类型然后再调用子类特有方法
if let dog = pet as? Dog {
dog.keepTheDoor()
}
else if let cat = pet as? Cat {
cat.catchTheMouse()
}
else if let mis = pet as? Mistress {
mis.makeTrouble()
}
}
let empsArray = [
Manager(name: "王大锤"),
Programmer(name: "骆昊"),
Programmer(name: "余婷"),
Salesman(name: "广告莎"),
Salesman(name: "欧阳坚"),
Programmer(name: "周鸿祎")
]
for emp in empsArray {
if let worker = emp as? Programmer {
print("请输入\(worker.name)本月工作时间: ", terminator: "")
worker.workingHour = inputInt()
}
else if let worker = emp as? Salesman {
print("请输入\(worker.name)本月销售额: ", terminator: "")
worker.sales = inputDouble()
}
// 员工工资的计算属性是重写过的多态行为
print("\(emp.name)本月工资为: ¥\(emp.salary)元")
}
通用随机函数
func randomInt(min: UInt32, _ max: UInt32) -> Int {
return Int(arc4random_uniform(max - min + 1) + min)
}
三角形面积公式(海伦公式)
// halfP为: 周长/2
sqrt(halfP * (halfP - ab) * (halfP - bc) * (halfP - ca))
面向对象七大终极原则:
☆面向对象的七大原则:
1) 开闭原则;------面向扩展开放,面向修改关闭。
2) 里氏转换原则;———超类存在的地方,子类是可以替换的。
3) 依赖倒转原则;------实现尽量依赖抽象,不依赖具体实现。
4) 接口隔离原则;------应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。
5) 组合/聚合复用原则;------尽量使用合成/聚合达到复用,尽量少用继承。原则:一个类中有另一个类的对象。
6) “迪米特”法则;------又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。
7) 单一职责原则。-----每一个类应该专注于做一件事情。