美文网首页
Swift学习 - 第三周知识整理

Swift学习 - 第三周知识整理

作者: 奈何乘风 | 来源:发表于2016-08-13 16:53 被阅读0次

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

    var a: Set<Int> = [1, 2, 3, 1, 2, 5]
    a.insert(100)           // 添加元素
    a.remove(2)             // 删除元素
    print(a)
    var b: Set<Int> = [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<Int> = [1, 3]
    print(c.isSubsetOf(a))      // 判断c是不是a的子集
    print(a.isSupersetOf(c))    // 判断a是不是c的超集
    
    let d: Set<Int> = [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..<array.count] {
            if value < currentMin {
                currentMin = value
            }
            else if value > 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..<month - 1] {
    //        sum += days
    //    }
        for i in 0..<month - 1 {
            sum += daysOfMonth[i]
        }
        if isLeapYear(year) && month > 2 {
            sum += 1
        }
        return sum + day
    //    var num = 0
    //    for i in 1..<month {
    //        switch i {
    //        case 3, 5, 7, 8, 10: num += 31
    //        case 4, 6, 9, 11: num += 30
    //        case 2:
    //            if isLeapYear(year) {
    //                num += 29
    //            }
    //            else {
    //                num += 28
    //            }
    //        default: break
    //        }
    //    }
    //    return num + day
    }
    print("请输入年,月,日:", terminator: "")
    let num1 = inputInt()
    let num2 = inputInt()
    let num3 = inputInt()
    print("这是一年中的第\(daysOfYear(num1, num2, num3))天")
    

    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..<array.count] {
            sum = fn(sum, x)
        }
        return sum
    }
    
    let a = [1, 2, 3, 4, 5]
    // 当调用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 })
    
    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<UITouch>, 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..<cardsArray.count {
                let j = randomInt(0, UInt32(cardsArray.count - 1))
                (cardsArray[i], cardsArray[j]) = (cardsArray[j], cardsArray[i])
            }
        }
        
        /**
         发牌
         - returns: 当前剩下牌中的第一张牌或nil
         */
        func deal() -> 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) 单一职责原则。-----每一个类应该专注于做一件事情。
    

    相关文章

      网友评论

          本文标题:Swift学习 - 第三周知识整理

          本文链接:https://www.haomeiwen.com/subject/udiesttx.html