Swift第四周(第一月)总结

2016-08-20  本文已影响0人  Daniel01

沉迷学习,日渐消瘦,一天不学习,浑身难受。

学习Swift已过一个月,已经从零基础到入门,能够逐渐理顺思绪,找到关键点。

swift副本.jpg

协议

注释: 协议在Swift开发中大致有三种作用:

  1. 能力 - 遵循了协议就意味着具备了某种能力
  2. 约定 - 遵循了协议就一定要实现协议中的方法
  3. 角色 - 一个类可以遵循多个协议, 一个协议可以被多个类遵循, 遵循协议就意味着扮演了某种角色, 遵循多个协议就意味着可以扮演多种角色
  1. 抽象是关键(在设计系统的时候一定要设计好的协议);
  2. 封装可变性(桥梁模式 - 将不同的可变因素封装到不同的继承结构中)

注释:接口(协议)隔离原则: 协议的设计要小而专不要大而全
协议的设计也要高度内聚

protocol Flyable {
    
    func fly()
}
protocol Fightable {
    
    func fight()
}

协议扩展

协议扩展 - 可以在协议扩展中给协议中的方法提供默认实现
也就是说如果某个类遵循了协议但是没有实现这个方法就直接使用默认实现
那么这个方法也就相当于是一个可选方法(可以实现也可以不实现)

extension Fightable {
    
    func fight() {
        print("正在打架")
    }
}
// 协议的继承
protocol NiuBi: Flyable, Fightable { 
    func dive()
}
class Boxer: Fightable {
    
    @objc func fight() {
        print("正在进行格斗.")
    }
}
  1. 声明变量的类型时应该尽可能使用协议类型
  2. 声明方法参数类型时应该尽可能使用协议类型
  3. 声明方法返回类型时应该尽可能使用协议类型
et x: protocol<Flyable, Fightable> = Superman()
let y: NiuBi = Superman()
let array: [protocol<Flyable, Fightable>] = []

计算机属性:

计算机的硬件由五大部件构成:
运算器、控制器、存储器、输入设备、输出设备
运算器 + 控制器 => CPU (中央处理器)
存储器 => 内存 (RAM - Random Access Memory)

程序员可以使用的内存大致分为五块区域:

栈 (stack) - 我们定义的局部变量/临时变量都是放在栈上

值和类型的区别:

** 结论:** 我们自定义新类型时优先考虑使用类而不是结构除非我们要定义的是一种底层的数据结构(保存其他数据的类型)

引用类型的类
let stu1 = Student1(name: "骆昊", age: 35)
var stu3 = stu1     // 此处内存中仍然只有一个学生对象
stu3.name = "罗小号"
stu3.age = 18
print(stu1.name)
print(stu1.age)
et stu2 = Student2(name: "骆昊", age: 35)
var stu4 = stu2     // 此处内存中会复制一个新的学生对象
stu4.name = "王大锤"
stu4.age = 18
print(stu2.name)
print(stu2.age)
mutating func getOlder() {
        age += 1
    }
}
在Swift中同名函数只要参数列表不同是可以共存的 这个叫函数的重载
func changeName(inout name: String) {
    name = "王大锤"
}

协议委托回调:

有的时候某个对象要做某件事情但其自身又没有能力做这件事情,这个时候就可以使用委托回调的编程模式让别的对象来做这件事情

实现委托回调的编程模式有以下几个步骤:

  1. 设计一个协议(被委托方必须要遵循协议才能给别的对象当委托)
protocol CanvasDelegate: class {

协议里面的方法就是要委托其他对象做的事情

unc showMessage(canvas: Canvas, message: String)
}
  1. 委托方添加一个属性其类型是遵循了协议的被委托方
class Canvas: UIView {
    // 2. 委托方添加一个属性其类型是遵循了协议的被委托方
     weak var delegate: CanvasDelegate?
     var renjuBoard = RenjuBoard()
    var isAutoMode = false
    func clearBoard() {
        renjuBoard.reset()
        setNeedsDisplay()
    }
    func randomMove() {
        let row = Int(arc4random_uniform(15))
        let col = Int(arc4random_uniform(15))
        if renjuBoard[row, col] {
            renjuBoard[row, col] = renjuBoard.isBlackTurn
            setNeedsDisplay()
        }
    }
  1. 自己做不了的事情委托给别的对象来做
delegate?.showMessage(self, message: renjuBoard.isBlackTurn ? "白棋胜" : "黑棋胜")

其他:

 Swift 2中的guard大法, Swift 3中据说要废掉
        guard !isAutoMode else { return }
        // guard !renjuBoard.isGameOver else { return }
    // 索引器语法 - 可以直接对棋盘对象做下标运算来放置棋子
    subscript(row: Int, col: Int) -> Bool {
        get { return board[row][col] == .Space }
        set(isBlack) {
            if board[row][col] == .Space {
                board[row][col] = isBlack ? .Black : .White
                isBlackTurn = !isBlackTurn
            }

指派构造器:

指派构造器(designated)
    required init(name: String, age: Int) {
        print("创建一个人!")
        self.name = name
        self.age = age
    }

注释:指派构造器前面加上required可以将构造器指定为必要构造器
所谓的必要构造器意味着子类也要提供一模一样的构造器

        self.major = major
        self.init(name: name, age: age)
        self.major = major
        初始化的第一阶段
          1. 初始化自己特有的属性
       self.major = major
       // 子类只能调用直接父类的构造器
        // 子类构造器必须调用父类的非便利构造器(指派构造器)
 super.init()    // compiler error
        //  2. 调用父类的初始化方法
        super.init(name: name, age: age)
 //初始化的第二阶段
       // 此处可以调用对象的方法因为对象已经完成了初始化
        study()
    }
      func study() {
        print("\(name)正在学习.")
    }
     deinit {
        print("学生对象嗝屁了!")
    }
}
class Teacher: Person {
    deinit {
        print("老师对象嗝屁了!")
    }
}
 stu = Teacher()
 stu = Person()
> 将来做iOS开发时如果某个地方会创建很多的临时对象.   那么最好在此处设置一个自动释放池避免内存瞬时峰值过高造成闪退
     let stu1 = Student()
     let stu2 = stu1
 }

离开自动释放池时 stu1会收到引用计数-1消息 stu2也会收到引用计数-1消息

注释:
推荐使用
如果允许使用可空类型通常使用weak来破除循环引用
如果员工关联的部门对象被释放了那么dept会被赋值为nil
如果要继续给dept对象发消息程序不会崩溃
weak var dept: Dept?

 谨慎使用
 如果不允许使用可空类型就必须使用unowned来破除循环引用
 需要注意的是如果员工对象关联的部门对象被释放了
 如果还要通过员工对象去操作它所关联的部门对象将导致程序崩溃
 EXC_BAD_ACCESS

泛型 (generic)

// 定义一个虚拟类型T, 调用函数时根据传入的参数类型来决定T到底是什么
func mySwap<T>(inout a: T, inout _ b: T) {
    let temp = a
    a = b
    b = temp
}

2.泛型限定

// <T: Comparable>限定T类型必须是遵循了Comparable协议的类型
func myMin<T: Comparable>(a: T, _ b: T) -> T {
    return a < b ? a : b
}

注释:wift中的类、结构和枚举都可以使用泛型:

struct Stack<T> {
    var data: [T] = []
    
    // 入栈
    mutating func push(elem: T) {
        data.append(elem)
    }
    
    // 出栈
    mutating func pop() -> T {
        return data.removeLast()
    }
    
    var isEmpty: Bool {
        get { return data.count == 0 }
    }
}

抛错误异常

init(num: Int, den: Int) throws {
        _num = num
        _den = den
        if _den == 0 {
            // 如果程序中出现问题就抛出错误(异常)
            // 被throw关键字抛出的必须是遵循ErrorType协议的东西
            throw FractionError.ZeroDenominator
        }
        else {
            simplify()
            normalize()
        }
    }

But:
1.如果能够确保方法调用时不出异常那么可以在try关键字后加!
2.这样就可以在不写do...catch的情况下调用可能出状况的方法

注释:如果能够保证代码不出错可以在try后面加!
1.如果不确定代码是否出错可以在try后面加?
2.需要注意的是有?的地方会产生Optional(可空类型)
稍后可能还需要对可空类型进行拆封, 拆封方式有二:
1. 不安全的做法: xxx!
2. 安全的做法: 用if let = xxx { }进行拆封

    let f1 = try? Fraction(num: 3, den: 0)
    let f2 = try? Fraction(num: 0, den: 9)
    
    if let a = f1, b = f2 {
        let f3 = a + b
        print(f3.info)
    }
    else {
        print("无效的分数无法进行加法运算")
    }
}
foo

注释:
1.对于可能出状况的代码要放在do...catch中执行.
2.在可能出状况的方法前还要写上try表示尝试着执行
3.如果在do中没有出现任何状况那么catch就不会执行
4.如果do中出现了状况代码就不会再向下继续执行而是转移到catch中
5.在do的后面可以跟上多个catch用于捕获不同的异常状况 但是最多只有一个catch会被执行

do {
    let f1 = try Fraction(num: 3, den: 4)
    let f2 = try Fraction(num: 0, den: 9)

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

    let f3 = f1 + f2
    print(f3.info)
    let f4 = f1 - f2
    print(f4.info)
    let f5 = f1 * f2
    print(f5.info)
    let f6 = try f1 / f2
    print(f6.info)
}
catch FractionError.ZeroDenominator {
    print("瓜西西的, 分母不能为0!!!")

总结:

相对于这几周的语法相对于比较枯燥和难一些,攻破了这个之后的路就能更为顺畅一些,在之后的日子更要努力。

上一篇 下一篇

猜你喜欢

热点阅读