错误处理
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的对象,需要给出变量和方法的实现。它的特点:
- class/struct/enum都可以实现protocol;也可以在extension中实现protocol
- protocol支持多继承;protocol中可选的方法需要声明为optional,同时该protocol需加
@Objc
, 而实现该protocol的对象需继承自NSObject
- protocol中声明的var需要声明是否可以 get/set;声明的方法如果可以改变对象自身需要声明
mutating
- 不能重载已有的方法或属性,只能添加computed型属性
- 如果只希望class对象实现protocol,在声明protocol时使其继承自
class
;mutating
关键字也可以省略 - 因为protocol本身是一种类型,可以直接声明某个变量为某个protocol,这一点和ObjC不一样
高级用法
-
结合泛型,protocol变得强大
面向对象的思想告诉我们,某些对象具有相同的特性时我们需要使用某种机制来明确该特性。一些情况下,这些对象如果可以追本溯源的话,会使用继承。否则,就可以使用protocol。鸟会飞,飞机也会飞,此时飞就无法作为某种相同/似物体的特性而存在。合理的方法,就应该定义protocol,只要是会飞的,就实现该protocol。
注意,这已经是一种基本的设计思维。 -
多继承
首先多继承可以实现对相关protocol的自由组合,增加了灵活性。同时因为protocol是一种类型,针对protocol的通用代码,对所有实现protocol的对象都是有效的,减少了重复。
我觉得这一点可以结合1一起考虑。 - extension增加protocol的威力
extension中可以添加protocol的默认实现,这同样减少了重复提高效率。视频中提到Sequence protocol通过extension实现了一组默认的方法,因此一旦定义了实现Sequence的对象,就默认实现了 contains(), forEach(), joined(separator:), min(), 和max()等方法。 - 函数式编程
只是提及,我也没有实际使用经验。这是一个热门趋势,值得研究。 - 设计模式: 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。该关键字可以使修饰的变量/方法在当前文件内,都是可用的;而通过继承等其他手段,都是不可见的。
Comments