swift第三周学习总结


1. 集合(Set)


哈希码(hash code)、散列码、MD5 、SHA - 1

(1)集合的定义:

  是无序无重复的数据集.
  它所存储的元素的类型必须是一致的,
  同样,我们取出来的数据类型也是明确的。

(2)集合写法:

写法是一行用逗号隔开的值,并在行的两端用一对方括号包起来: 
[value 1, value 2, value 3]

举例:

var a = [1, 2, 3, 1, 2, 5]
print(a)             //依次全部打印出来

var a: Set = [1, 2, 3, 1, 2, 5]
print(a)            //打印出的是去掉了重复的值

//根据数值可以推断出数组a是Int类型的。

 注意:
 集合a被声明为变量(var)而不是常量(let),
 是因为在下面的例子中会往这个数组里添加更多的元素。

(4)对集合的操作:

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(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))  // 判断两个集合是否相交

2. 字典(Dictionary)

(1)字典的定义:

字典是一种存储多个类型相同的键值对组合的容器。

(2)特点:

1.每个值都和一个唯一的键相对应,
  这个键在字典里就是其对应值的唯一标识。
2.字典中的每个元素都是由两部分构成的,
  冒号前面是键冒号后面是值
3.跟数组不同,字典里的元素并没有特定的顺序。
4.在“字典”中使用键来查询其对应值的方式,
  跟在“现实世界的字典”中使用单词查询单词定义差不多。
5.通过键获取对应的值
 (可空类型,因为给的键有可能没有与之对应的值)  
  key ---> value

(3)写法:

键值对是一个键和一个值的组合,
每对键值对中的键和值使用冒号分开,
键值对之间用逗号分开,
用一对方括号将这些键值对包起来:
[key 1: value 1,  key 2: value 2,  key 3: value 3]

举例:

var dict = ["abacus":"算盘","abnormal":"异常的","hello":"你好","good":"好的"]

print(dict["hello"]!)
print(dict["abcxyz"])

(4)对字典的操作:

//添加元素
dict["shit"] = "狗屎"
dict["fuck"] = "操"
dict["delicious"] = "好吃的"
print(dict)

//删除元素
//dict.removeValueForKey("hello")
dict["hello"] = nil
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)")
}

(5)总结:

数组和字典都把多个值存放在一个集合里。
如果你创建了一个数组或者字典,
并且将之指定为变量,
那么该集合就是可变的,
这意味着在集合被创建后,
可以通过增加或删除元素来改变集合的容量大小。
相反地,如果你指定一个数组或字典为常量,
那么该数组或字典就是不可变的,其容量大小不能被改变。
对字典来说,
不可变还意味着你不能改变字典里某个键的值。
一个不可变的字典一旦被设置值后,
它里面的内容就不能再改变。

3. 函数

(1)函数的定义

 定义函数
 func 函数名(参数列表) -> 返回类型 { 函数的执行体 }
 函数名(外部参数名 内部参数名: 类型, 外部参数名 内部参数名: 类型)
 Swift中函数的参数可以设定默认值。
 如果调用函数的时候没有给该参数赋值就直接使用默认值。

(2)注意点:

1.如果不写外部参数名那么内部参数名也是外部参数名
2.可以使用 _ 来作为外部参数名表示省略外部参数名
    func myMin(a x: Int, b y: Int) -> Int {
    return x < y ? x : y           //有外部参数名
    }
    func myMin(x: Int, _ y: Int) -> Int {
        return x < y ? x : y          //省略了外部参数名
    }
    
3.调用函数的时候要写函数的外部参数名
print(myMin(a: 3, b: 5))

4.调用函数的时候省略了外部的参数名
print(myMin(3, 5))
5.如果调用函数的时候没有给该参数赋值就直接使用默认值
6.如果函数的返回类型不是Void 那么函数中一定有return语句
func sayHello(personName: String, alreadyGreeted: Bool = false) -> String {
    // let greeting = "Hello, " + personName + "!"
    // 如果函数的返回类型不是Void 那么函数中一定有return语句
    // return greeting
    // personName = "王小锤"   // 编译错误
    if alreadyGreeted {
        return "怎么又是你, " + personName + "!"
    }
    else {
        return "你好, " + personName + "!"
    }
}

(3)调用函数

1.调用Swift的函数时, 在默认情况下从第二个参数开始需要写参数名
print(sayHello("王大锤", alreadyGreeted: true))
// 如果没有给第二个参数赋值那么就直接使用默认值false
let str = sayHello("Jack")
print(str)
2.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))

3.可以使用元组(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)")

(3)无参函数

1.  函数并没有要求一定要定义的输入参数。
    下面就一个没有输入参数的函数,
    任何时候调用时它总是返回相同的字符串消息:
func sayHelloWorld() -> String {
    return "hello, world"
}
print(sayHelloWorld())
2.  注意:该函数的定义在函数的名称后还需要括号,
    即使它不带任何参数。
    当函数被调用时函数名称也要跟着一对空括号。

(3)使用函数的小知识点

 在Swift中函数是一种类型
这也就意味着函数可以作为变量或常量的类型
同理函数也可以作为另一个函数的参数或返回值
func sum(a: Int, _ b: Int) -> Int {
    return a + b
}

func mul(a: Int, _ b: Int) -> Int {
    return a * b
}
//把一个函数当作了另一个函数的参数
func foo(array: [Int], fn: (Int, Int) -> Int) -> Int {
    var sum = array[0]
    for x in array[1..

当调用foo函数时第二个参数可以传什么?
// 1. 所有自定义的(Int, Int) -> 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 })

(4)尾随闭包

1.如果函数的最后一个参数是闭包可以写成尾随闭包的形式
也就是将闭包放到函数参数的圆括号外面写在一对花括号中
3.如果函数后面有尾随闭包且函数的圆括号中没有参数
那么函数的圆括号也可以省略(仅限于有尾随闭包的场景)
import Foundation

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)

(5)对于函数的一些用例

  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("阿郎"))

2.设计一个函数传入两个正整数m和n, 计算从m加到n的和

func sum(m: Int, _ n: Int) -> Int {
    let (a, b) = m > n ? (n, m) : (m, n)
    var value = 0
    for i in a...b {
        value += i
    }
    return value
}

print(sum(1, 100))
print(sum(5, -4))

3.设计一个函数输入三条边的长度,判断能不能构成三角形
func isViewForTriangle(a:Double, _ b:Double, _ c:Double) -> Bool {
    assert(a > 0 && b > 0 && c > 0, "三边必须大于0!")
    return a + b > c && b + c > a && c + a > b
}
print(isViewForTriangle(3,  4,  5))

4.设计一个函数传入年月日返回该日期是这一年的第几天

func daysofYear(year:Int, month:Int, day:Int) -> Int {
    let daysofmonth = [31,28,31,30,31,30,31,31,30,31,30,31]
    var sum = 0
    for i in 0.. 2 {
        sum += 1
    }
    return sum + day
}
func isLeapYear(year:Int) -> Bool {
    return year % 4 == 0 && year % 100 != 0 || year % 400 == 0
}
print("这是第\(daysofYear(1980, month: 11, day: 28))天")


5.设计一个函数计算组合数C(m,n) = m!/n!/(m-n)!

func factorial1(n:Int) -> Double {
    var product = 1.0
    for i in 1...n {
        product *= Double(i)
    }
    return product
}
func combine(m: Int,n: Int) -> Double {
//    var sum:Double
//    let (a, b) = m < n ? (n, m) : (m, n)            //函数中不用判断输入的数的有效性!
//    sum = factorial1(a) / factorial1(b) / factorial1(a - b)
    assert(m > n,"m必须大于等于n!")
    return factorial1(m) / factorial1(n) / factorial1(m - n)
}
print("组合数为:\(combine(5, n: 3))")

6.求阶乘!

func factorial(n:Int) -> Double {
    var product = 1.0
    for i in 1...n {
        product *= Double(i)
    }
    return product
}
print(factorial(10))

(6)函数的递归调用

函数的递归调用(一个函数直接或间接的调用自身)
func f(n:Int) -> Double {
    if n == 0 || n == 1 {
        return 1
    }
    return Double(n) * f(n - 1)
}
print(f(5))

//(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(5 , "A",  "B", "C")

4. 对于数组的补充

1.过滤
2.映射
3.缩减
let array = [23, 37, 96, 55, 40, 92, 68, 88]

// 1. 过滤

let newArray1 = array.filter { $0 > 50 }     //取大于50的
print(newArray1)
let newArray2 = array.filter { $0 % 2 == 0}   //取偶数
print(newArray2)

// 2. 映射

let newArray3 = array.map { $0 / 2}
print(newArray3)
let newArray5 = array.map { sqrt(Double($0)) }
print(newArray5)

// 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)

5.类的创建

步骤:
1.定义类(如果你要用的类苹果已经提供了就直接进入第2步) 
  定义类就可以创建出新的类型
2.创建对象(调用初始化方法)
3.给对象发消息(通过给对象发消息来解决问题)
// 学生类
//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), 我们推荐你观看《熊出没》")
//        }
//    }
//}
//
// 创建对象(调用初始化方法)
//let stu1 = Student(name: "阿郎", age: 35)
//  给对象发消息(通过给对象发消息来解决问题)
//stu1.eat()
//stu1.study("Swift程序设计")
//stu1.watchJapaneseAV()
//
//let stu2 = Student(name: "王大锤", age: 15)
//stu2.eat()
//stu2.study("中国近代史")
//stu2.watchJapaneseAV()
举例:
// 定义了一个叫 钟 的类
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()
}

6.类的实例

说明:
在main.swift 中我们只写 创建对象 和 给对象发消息。
我们在 swift.fill 中新建一个文件来存放新定义的类!
举例:
  1. 定义了一个叫 点 的类

放在Point.swift文件中的定义类

// 定义了一个叫 点 的类
class Point {
    var x: Double
    var y: Double
    
    // 我们可以在一个类中定义多个初始化方法
    
    // 便利初始化方法 / 便利构造器
    // 调用了其他的初始化方法的初始化方法
    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
    }
}

放在main.swift文件中的 创建对象 和给对象发消息

let p1 = Point()
let p2 = Point(x: 3, y: 4)
let p3 = Point(point: (-3.5, 6.7))

print(p1.distanceTo(p2))
print(p2.distanceTo(p3))

2.定义了一个叫 线段 的类

放在Line.swift文件中的定义类

//直线
class Line {
    var start: Point
    var end: Point
    
    init(start: Point, end: Point) {
        self.start = start
        self.end = end
    }
    
    func intersects(other: Line) -> Bool {
        
        return false
    }
    
    var length: Double {
        get { return start.distanceTo(end) }
    }
}

放在main.swift文件中的 创建对象 和给对象发消息

let line = Line(start: p2, end: p3)
print(line.length)

3.定义了一个叫 猜数字游戏 的类

放在Robot.swift文件中的定义类
//猜数字
class Robot {
// 数据抽象
var answer: Int // 正确答案
var counter = 0 // 猜的次数
var hint = "" // 提示信息

// 初始化方法
// 保证所有的存储属性都被初始化(有值)
init() {
    answer = Int(arc4random_uniform(100)) + 1
}

// 行为抽象
// 判断
func judge(thyAnswer: Int) -> Bool {
    counter += 1
    if thyAnswer < answer {
        hint = "大一点"
        return false
    }
    else if thyAnswer > answer {
        hint = "小一点"
        return false
    }
    else {
        hint = "恭喜你猜对了! 你总共猜了\(counter)次"
        return true
    }
}

}
放在main.swift文件中的 创建对象 和给对象发消息

 猜数字
let r = Robot()
var isGameOver = false
repeat {
    print("请输入你猜的数字: ", terminator: "")
    let thyAnswer = inputInt()
    isGameOver = r.judge(thyAnswer)
    print(r.hint)
} while !isGameOver

if r.counter > 7 {
    print("智商拙计!!!")
}

4.定义了一个叫 游泳池造价 的类

放在Circle.swift文件中的定义类

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 }
    }
}

放在main.swift文件中的 创建对象 和给对象发消息

let r = 5.5
// 创建对象
let small = Circle(radius: r)
let big = Circle(radius: r + 3)
// 给对象发消息(调用对象的方法)
let fencePrice = big.perimeter * 1.5
print(NSString(format: "围墙的造价为: ¥%.1f元", fencePrice))
let aislePrice = (big.area - small.area) * 3.5
print(NSString(format: "过道的造价为: ¥%.1f元", aislePrice))

小知识点:
 访问修饰符
 . public (公开)
 . internal (内部的) - 默认
. private (私有)

7.在App中类的应用

在App中创建一个画板,再引用三角形(Triangle)的类,在画板上用手随机点三下,就会画出一个以三点为基点的三角形。

(1). 在Triangle.swift 中定义 三角形的类:
//扩展(重点)
//如果在某个特定的应用场景中你发现现有的类缺少某项功能
//那么可以通过类扩展(extension)的方式现场添加这项功能
extension Point {
    var cgPoint:CGPoint {
        get { return CGPointMake(CGFloat(x), CGFloat(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()
//        let currentColor = color ?? UIColor.blueColor()
//        let currentColor = color == nil ? UIColor.blueColor() : color!
 //       currentColor.set()
        bezierPath.stroke()
        
    }
    
}
(2).在 ViewController.swift 中定义一个画板
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let c = Canvas(frame:self.view.bounds)
        c.backgroundColor = UIColor.clearColor()
        self.view.addSubview(c)
    }


}
(3).在 Canvas.swift 中用贝塞尔曲线画三角形
import UIKit

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)) }
    }
}


extension UIColor {
    
    static func randomColor() -> UIColor {
        let r = CGFloat(randomInt(0, 255)) / 255.0
        let g = CGFloat(randomInt(0, 255)) / 255.0
        let b = CGFloat(randomInt(0, 255)) / 255.0
        return UIColor(red: r, green: g, blue: b, alpha: 1)
    }
}

class Canvas: UIView {
    
    var pointsArray: [Point] = []
    var trisArray:[Triangle] = []
    
    override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
        if let touch = touches.first {
            let touchPoint = touch.locationInView(self)
            pointsArray.append(touchPoint.myPoint)
            if pointsArray.count == 3 {
                let t =  Triangle(va: pointsArray[0], vb: pointsArray[1], vc: pointsArray[2])
                
                t.color = UIColor.randomColor()
                
                //t.color = UIColor.redColor()
                trisArray.append(t)
                setNeedsDisplay()
                //清除原有的数据
                pointsArray.removeAll()
            }
        }
    }
    
    override func drawRect(rect: CGRect) {
        for t in trisArray {
            t.draw()
        }
    }


}
(4)效果截图
swift第三周学习总结_第1张图片
屏幕快照 2016-08-13 上午11.46.40.png
说明:
当然,在这里还引用了Point的类型,在你创建项目时,还得吧Point.swift文件拉进来。

8.练习用例

1.奥特曼打小怪兽

新建一个UItraman.swift的文件

import Foundation

//奥特曼
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 name:String {
        get { return _name }
    }
    //生命值
    var hp:Int {
        get { return _hp}
        set { _hp = newValue > 0 ? newValue : 0}
    }
    //魔法值
    var mp:Int {
        get { return _mp }
        set { _mp = 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
    }
}

再建一个Monster.swift文件

import Foundation

//小怪兽
class Monster {
    private var _name:String
    private var _hp:Int
    
    var name:String {
        get { return _name }
    }
    
    
    func isAlive() -> Bool {
        if _hp > 0 {
            return true
        }
        else {
            return false
        }
    }

        
    var hp:Int {
        get {
            return _hp
        }
        set {
            _hp = newValue > 0 ? newValue : 0
        }
    }
    
    init(name:String,hp:Int) {
        _name = name
        _hp = hp
    }
    
    
    func attack(ultraman: UItraman) {
        let injuary = randomInt(5, 10)
        ultraman.hp -= injuary
    }
}

main.swift文件

import Foundation

//奥特曼打小怪兽
//从一群小怪兽中挑出一只活的小怪兽
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: 150),
    Monster(name: "欧阳坚", hp: 250),
    Monster(name: "张尼玛", hp: 180),
    Monster(name: "李尼玛", hp: 130)
    ]

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:
        print("\(u.name)奥特曼使用了吞天食地")
        if u.magicalAttack(mArray) {
            for m in mArray {
                if m.isAlive() {
                      m.attack(u)
                }
              }
            }
        else {
                u.attack(m)
                if m.isAlive(){
                    m.attack(u)
                }
            }
    default:
        print("\(u.name)奥特曼使用了动感光波!!")
        u.hugeAttack(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.hp > 0 && !isAllDead(mArray)

if u.hp > 0 {
    print("\(u.name)奥特曼获胜!")
}
else {
    print("小怪兽获胜!!!")
}

运行后效果截图:

![屏幕快照 2016-08-13 下午2.09.24.png](./屏幕快照 2016-08-13 下午2.09.24.png)

2. 分数的加、减、乘、除运算

Fraction.swift文件中:

import Foundation


//最大公约数(短除法)
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
    }
    
   
    // 加
    func add(other:Fraction) -> Fraction {
        return Fraction(num: _num * other._den + other._num * _den, den: _den * other._den).simplify().normalize()
    }
    // 减
    func sub(other:Fraction) -> Fraction {
        return Fraction(num: _num * other._den - other._num * _den, den: _den * other._den).simplify().normalize()
    }
    // 乘
    func mul(other:Fraction) -> Fraction {
        return Fraction(num: _num * other._num, den: _den * other._den).simplify().normalize()
    }
     //  除
    func div(other:Fraction) -> Fraction {
        return Fraction(num: _num * other._den, den: _den * other._num).simplify().normalize()
    }

    //将负号放到分子上
    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)
}

main.swift文件中:

let f1 = Fraction(num: 3, den: 5)
let f2 = Fraction(num: 15, den: 9)

print(f1.info)
print(f2.info)

let f3 = f1 + f2
print(f3.info)

let f4 = f1 - f2
let f5 = f1 * f2
let f6 = f1 / f2
print(f4.info)
print(f5.info)
print(f6.info)
效果截图:

![屏幕快照 2016-08-13 下午2.21.16.png](./屏幕快照 2016-08-13 下午2.21.16.png)

3.扑克牌

Card.swift文件中:

import Foundation

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.swift文件中:

import Foundation

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.swift文件:

import Foundation

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(<)
    }
}

main.swift文件:

import Foundation

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)
}
效果截图:

![屏幕快照 2016-08-13 下午2.29.20.png](./屏幕快照 2016-08-13 下午2.29.20.png)

9.继承

(1).继承的定义:
一个类可以继承(inherit)另一个类的方法(methods),
属性(property)和其它特性。
当一个类继承其它类时,继承类叫子类(subclass),
被继承类叫超类(或父类,superclass)。
(2).定义一个基类(Base class)
不继承于其它类的类,称之为基类(base calss)。

注意:Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。

下面的例子定义了一个叫Pet的基类。这个基类声明了三个对所有宠物都通用的属性(nickname、gender和age)。

import Foundation

// 宠物
enum Gender {
    case Male
    case Female
}

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 eat() {
        print("\(nickname)正在吃东西。")
    }
    
    func play() {
        print("\(nickname)正在玩耍。")
    }
    
    func shout() {
        print("\(nickname)发出了叫声!")
    }
}
(3). 子类生成(Subclassing)
子类生成(Subclassing)指的是在一个已有类的基础上创建一个新的类。
子类继承超类的特性,并且可以优化或改变它。
你还可以为子类添加新的特性。
class Cat: Pet {
        //类的定义
}
下一个例子,定义一个更具体的宠物类叫Cat。
这个新类是在 Pet类的基础上创建起来。
因此你需要将Pet类放在Cat类后面,用冒号分隔。

我们可以将这读作:“定义一个新的类叫Cat,它继承了Pet的特性”:
import Foundation
// 猫
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()       // 调用了父类的play方法
        print("\(nickname)正在玩毛线团。")
    }
    
    override func shout() {
        print("\(nickname):喵喵喵......")
    }
    
    func catchTheMouse() {
        print("\(nickname)正在抓。")
    }
    
}
注意:子类还可以继续被其它类继承
重写(Override):
1.子类可以为继承来的实例方法(instance method),
类方法(class method),实例属性(instance property),
或附属脚本(subscript)提供自己定制的实现(implementation)。我们把这种行为叫重写(overriding)。
2.简单的说就是父类有的方法子类可以重现实现。
3.如果要重写某个特性,你需要在重写定义的前面加上override关键字。这么做,你就表明了你是想提供一个重写版本,而非错误地提供了一个相同的定义。意外的重写行为可能会导致不可预知的错误,任何缺少override关键字的重写都会在编译时被诊断为错误。

下一个例子,定义一个更具体的宠物类叫Dog。
这个新类是在 Pet类的基础上创建起来。
因此你需要将Pet类放在Dog类后面,用冒号分隔。
import Foundation

// 狗


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关键字
    // 重写有时也被称为置换/覆盖/覆写
    
    override func play() {
        super.play()       // 调用了父类的play方法
        print("\(nickname)正在接飞球。")
    }
    
    override func shout() {
        print("\(nickname):汪汪汪......")
    }
    
    func keepTheDoor() {
        if isLarge {
            print("\(nickname)正在看门。")
        }
        else {
            print("\(nickname)体型太小了,被操的节奏!")
        }
    }
    
}
(4).我们继续完善以上的例子:

我们可以在定义一个人的类(Person.swift),由人来领养宠物!

class Person {
    // Person和Pet之间是HAS-A(关联)
    var name:String
    var pet:Pet?    //可空类型
    
    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)正在自嗨")
        }
    }
    
}

main.swift文件:

let person = Person(name: "王大锤")
let dog = Dog(nickname: "小黄", gender: .Male, age: 1, isLarge: true)
let cat = Cat(nickname:"小咪咪", gender: .Female, age: 1)
person.adopt(cat)
person.strike()

效果截图:

![屏幕快照 2016-08-13 下午3.17.05.png](./屏幕快照 2016-08-13 下午3.17.05.png)

10.继承的实例练习

说明:
创建一个Person的基类,
两个继承了Person的子类(Student类和teacher类)。
(1)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() {
        print("\(name)正在吃饭")
    }
    
}
知识点:枚举
枚举为一系相关联的值定义了一个公共的组类型.同时能够让你在编程的时候在类型安全的情况下去使用这些值。

可以用enum开始并且用大括号包含整个定义体来定义一个枚举:

enum Gender {
    case Male
    case Female
}
注意:
1.枚举中定义的变量(像上例中Male、Female)是枚举的成员变量(或者说成员)。
2.关键字case是用来标明这一行将要定义一个新的成员变量。
3.每个枚举的定义都是定义了一个全新的类型,就像Swfit中的其他的类型一样,枚举的名称应该是以一个大写字母开头。
(2).Student子类:
import Foundation

class Student:Person {

    var major:String    //专业
    
    init(name:String,age:Int,major:String, gender:Gender) {
        self.major = major
        super.init(name: name, age: age, gender: gender)
        
    }
    
    func study(courseName:String) {
        print("\(name)是\(major)专业的学生")
        print("\(gender == .Male ? "他" : "她")正在学习\(courseName)")
    }
}
(3).Teacher子类:
class Teacher:Person {

    var title:String     //职称
    
    init(name:String,age:Int,title:String, gender:Gender) {
        self.title = title
        super.init(name: name, age: age, gender: gender)
    }
    
    func teach(courseName:String) {
        print("\(name)\(title)正在教\(courseName).")
    }
}

继承:从已有的类创建新类的过程,
提供继承信息的称为父类(超类/基类)
得到继承信息的称为子类(派生类/衍生类)
通常子类除了得到父类的继承信息还会增加一些自己特有的属性
所以子类的能力一定比父类更强大
继承的意义在于子类可以复用父类的代码并且增强系统现有的功能
(4).main.swift文件
import Foundation


let p1 = Person(name: "王大锤", age: 25, gender: .Male)
p1.eat()

//我们可以讲子类型的对象赋值给父类型的变量(因为子类跟父类之间是IS-A关系)
// 学生是人,老师是人,所以学生和 老师的对象可以赋值给人类型的变量

let p2:Person = Student(name: "张尼玛", age: 18, major: "计算机科学", gender: .Female)
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 = Teacher(name: "萝好", age: 35, title: "教授", gender: .Male)
p3.eat()
p3.teach("网页设计")

运行结果截图:

![屏幕快照 2016-08-13 下午3.38.41.png](./屏幕快照 2016-08-13 下午3.38.41.png)

11.多态

同样的对象类型(pet类型)接收相同的消息(调用相同的方法),
但是做了不同的事情 这就是多态(polymorphism)。

 实现多态的关键步骤:
 1. 方法重写(子类在继承父类的过程中对父类已有的方法进行重写,而且不同的子类给出各自不同的实现版本)
 2. 对象造型(将子类对象当成父类型来使用)

 可以通过if+as?将父类型安全的转换成子类型然后再调用子类特有的方法

根据继承中的Pet的例子:

let petsArray = [
    Cat(nickname: "加菲", gender: .Female, age: 2),
    Dog(nickname: "旺财", gender: .Male, age: 1, isLarge: true),
    Dog(nickname: "大黄", gender: .Male, age: 3, isLarge: false),
//    Mistress(nickname:"苍老师" ,gender:.Male, age: 15)
]

for pet in petsArray {
//    pet.eat()
//    pet.play()
    
    // 实现多态的关键步骤:
    // 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 mistress = pet as? Mistress {
        mistress.shout()
    }
}

效果截图:

![屏幕快照 2016-08-13 下午3.14.24.png](./屏幕快照 2016-08-13 下午3.14.24.png)

多态的实例练习:雇员工资的计算
(1).Employee基类

import Foundation

class Employee {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    var salary: Double {
        get { return 0 }
    }
}
(2).Manager子类
import Foundation

class Manager: Employee {
    
    override var salary: Double {
        get { return 12000 }
    }
}
(3)Programmer子类
import Foundation

class Programmer: Employee {
    var workingHour = 0
    
    override var salary: Double {
        get { return 200 * Double(workingHour) }
    }
    
}
(4)Salesman子类
import Foundation

class Salesman: Employee {
    var sales = 0.0
    
    override var salary: Double {
        get { return 1000 + sales * 0.05 }
    }
}

(5)main.swift
import Foundation

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)元")
}


运行截图:

![屏幕快照 2016-08-13 下午3.55.00.png](./屏幕快照 2016-08-13 下午3.55.00.png)

编程的终极原则: 高内聚, 低耦合
面向对象七原则:
1.单一职责原则(SRP) - 每一个类应该专注于做一件事情
2.开闭原则(OCP) - 面向扩展开放,面向修改关闭
3.依赖倒转原则(面向抽象编程, DIP) - 定义方法参数类型的时候尽可能使用父类型(抽象类型),因为如果用父类型的参数调用方法时可以传入任意子类型对象
4.里氏替换原则(LSP) - 能用父类型的地方就一定可以使用子类型
5.接口隔离原则(ISP) - 应当为客户端提供尽可能小的单独的接口,而不是提供大
的总的接口
6.合成聚合复用原则(CARP) - 尽量使用合成/聚合达到复用,尽量少用继承。原则:
一个类中有另一个类的对象
7.迪米特法则(LoD) - 又叫最少知识原则,一个软件实体应当尽可能少的与其
他实体发生相互作用

** 更多精彩筹备中....**
** 请关注 :老韩在!!!**

你可能感兴趣的:(swift第三周学习总结)