Stanford iOS10 笔记-L7 Error handling等

错误处理

func save() throws -> returnType

首先看函数定义, throws 表明 save 函数的执行会抛出错误;如果有返回值,该关键字在返回值之前。通常,调用会产生错误的函数时,使用 do-catch , do 块中调用可能产生错误的函数,在catch中处理该错误。其中 error 须是实现了 Error 协议的对象。对于含有 throws 的函数,调用时必须使用 try

do {
    try context.save()
} catch let error {
    throw error
}

关于try!和 try?

对于会产生错误且有返回值的函数,如果确信不会抛出错误,可以使用 try! 调用函数并获取返回值 (如果实际会产生错误,那么程序就crash了)。然通常会使用 try?,此时返回的是 optional。 详情可见 Error Handling Demo

let x = try? errorTest(num: -10.0)
print(type(of: x))

let y = try? errorTest(num: 10.0)
print(type(of: y))

let z = try! errorTest(num: 10.0)//crash if it is -10.0
print(type(of: z))

更多

使用 defer 来执行清理行为。因为函数可能会因为错误退出,那有可能会错过一些清理行为,如打开文件,存储内容时出错,这时就会错过文件的关闭。 通过 defer 可以把相关操作集中起来,当发生错误退出当前代码段前,执行相关操作。
在ObjC中,我们有 NSError 和 NSException,在Swift中,只有 Error。Error的行为和处理,非常类似 NSException。但是 Error囊括了 NSError 和 NSException。怎么理解? ObjC中,有一些方法,通过引用传值的方式,把可能的 NSError返回(如NSFileManager的API),但这取决于调用者——因为有些调用者不会去获取该NSError,从而错过关键信息。而在Swift中,只要含有throws,则必须使用 try,这样在语法上就避免了不处理错误的可能。
throws表明某函数会返回错误,rethrows则表明函数的某个参数会返回错误, 如:

func myFunc:(callback:() -> throws -> Void) rethrows

此时catch中只能处理rethrows的错误(即callback产生的错误)。

Extension

Extension可以在不知道源码的情形下,添加新的方法和属性(computed),是名副其实的"扩展"。很便利,但勿滥用,使用得好需要很强的功底。可以参照 ObjC 中 Category的概念使用,课中的例子是通过extension来获取VC的contentViewController。

Protocols

Swift中 protocols 是一种类型,声明了一组变量或方法。遵循该protocol的对象,需要给出变量和方法的实现。它的特点:

  1. class/struct/enum都可以实现protocol;也可以在extension中实现protocol
  2. protocol支持多继承;protocol中可选的方法需要声明为optional,同时该protocol需加@Objc, 而实现该protocol的对象需继承自NSObject
  3. protocol中声明的var需要声明是否可以 get/set;声明的方法如果可以改变对象自身需要声明 mutating
  4. 不能重载已有的方法或属性,只能添加computed型属性
  5. 如果只希望class对象实现protocol,在声明protocol时使其继承自 classmutating 关键字也可以省略
  6. 因为protocol本身是一种类型,可以直接声明某个变量为某个protocol,这一点和ObjC不一样

高级用法

  1. 结合泛型,protocol变得强大
    面向对象的思想告诉我们,某些对象具有相同的特性时我们需要使用某种机制来明确该特性。一些情况下,这些对象如果可以追本溯源的话,会使用继承。否则,就可以使用protocol。鸟会飞,飞机也会飞,此时飞就无法作为某种相同/似物体的特性而存在。合理的方法,就应该定义protocol,只要是会飞的,就实现该protocol。
    注意,这已经是一种基本的设计思维。

  2. 多继承 首先多继承可以实现对相关protocol的自由组合,增加了灵活性。同时因为protocol是一种类型,针对protocol的通用代码,对所有实现protocol的对象都是有效的,减少了重复。
    我觉得这一点可以结合1一起考虑。

  3. extension增加protocol的威力 extension中可以添加protocol的默认实现,这同样减少了重复提高效率。视频中提到Sequence protocol通过extension实现了一组默认的方法,因此一旦定义了实现Sequence的对象,就默认实现了 contains(), forEach(), joined(separator:), min(), 和max()等方法。
  4. 函数式编程 只是提及,我也没有实际使用经验。这是一个热门趋势,值得研究。
  5. 设计模式: Delegation 和ObjC一样,protocol广泛适用于 Delegation 模式(确切的说,应该是iOS经常使用Delegation模式)。用得最多的场景就是, View需要数据填充,通过Delegation的方式让 Controller提供; View需要应对某些操作相应,通过Delegation方式让 Controller响应。

UIScrollView 使用

UIScrollView的使用需要理解几个属性:

  • frame: 在父view坐标系,scrollView的位置和实际的大小
  • contentSize: 所含内容的宽高,可以选选大于frame的size
  • contentOffset: 当前content相对于frame origin的位置偏移;滚动的时候,该值会不断变化
  • contentInset: content显示内容相对于frame的距离;相当于word中文字内容和页面四边的距离

除此以外,熟悉ScrollView定义的delegate方法也能帮助灵活使用。

Swift

前面提到,extension对实现protocol、保持良好代码结构都很有帮助。通常,VC需要实现的protocol可以单独放在extension中。但VC中的private变量不能在extension中使用,此时可以使用 fileprivate。该关键字可以使修饰的变量/方法在当前文件内,都是可用的;而通过继承等其他手段,都是不可见的。