01.defer
使用defer指定的代码块, 会在defer所在的代码块执行结束时(结束后?)被调用, 如果出现多个defer的定义, 后定义的将会先执行.
func hello() {
defer {
print("defer - 1")
}
if true {
defer {
print("defer - 2")
}
print("defer - 3")
}
print("defer - 4")
}
/* console output:
defer - 3
defer - 2
defer - 4
defer - 1
*/
02.do-catch, try, throw, throws, rethrows
这些是swift异常处理的关键词.
实现一个函数(假定函数名为somefunc)时, 通过调用throw someError, 可以立刻中断函数. 此类函数名字的末尾需要指定throws关键词.
当调用此类函数时, 函数前需要加try关键词, 并且置于do的代码块中, 在catch的代码块中处理那个someError. 如果catch后不去指定变量名, 那么块中会使用默认变量名error.
也可以使用try?或者try!去调用这类函数, 此时不再需要do-catch, 该函数抛出异常时, 异常信息会被忽略. 如果函数有返回值, 接收该值的变量将会是optional类型(try?)或者非optional类型(try!).
也许函数somefunc本身的处理过程中, 不会抛出任何异常, 但是它会接收一个可能抛出异常的闭包作为参数. 在somefunc内部调用这个闭包时, 需要使用try, 不需要do-catch. 在somefunc的函数名字的末尾需要指定rethrows关键词.
func throwsome(n: Int) throws {
if n % 2 == 0 {
throw NSError(domain: "com.test.throws", code: 1000, userInfo: nil)
} else {
print("\(n) is ok")
}
}
do {
try throwsome(n: 10)
} catch {
print(error)
}
func rethrowsome(f: (Int) throws -> Void ) rethrows {
try f(10)
}
do {
try rethrowsome { n in
if n % 2 == 0 {
throw NSError(domain: "com.test.rethrows", code: 1001, userInfo: nil)
} else {
print("\(n) is ok")
}
}
} catch {
print(error)
}
/* console output:
Error Domain=com.test.throws Code=1000 "(null)"
Error Domain=com.test.rethrows Code=1001 "(null)"
*/
03.associatedtype
这个关键词用在协议中, 申明一个没有确定下来的类型, 在协议中的方法中, 就可以使用这个类型了.
实现这个协议的class/struct, 需要使用typealias将这个类型确定下来.
有点类似于泛型.
class Species {
let name : String
init(name : String) { self.name = name }
}
protocol FoodChainProtocol {
associatedtype Food where Food : Species
func eat(_ food: Food)
}
class Grass : Species {
init() { super.init(name: "grass") }
}
class Horse : Species, FoodChainProtocol {
init() { super.init(name: "horse") }
typealias Food = Grass
func eat(_ food: Food) { print("\(name) eat \(food.name)") }
}
class Tiger : Species, FoodChainProtocol {
init() { super.init(name: "tiger") }
typealias Food = Horse
func eat(_ food: Food) { print("\(name) eat \(food.name)") }
}
let grass = Grass()
let horse = Horse()
let tiger = Tiger()
horse.eat(grass)
tiger.eat(horse)
/* console output:
horse eat grass
tiger eat horse
*/
04.dynamic
由于 swift 是一个静态语言, 所以没有 Objective-C 中的消息发送这些动态机制, dynamic 的作用就是让 swift 代码也能有 Objective-C 中的动态机制, 常用的地方就是 KVO 了, 如果要监控一个属性, 则必须要标记为 dynamic.
class Observed: NSObject {
@objc dynamic var someValue: String = "123"
var otherValue: String = "abc"
}
class Observer: NSObject {
func ob() {
let object = Observed()
object.addObserver(self, forKeyPath: "someValue", options: .new, context: nil)
object.addObserver(self, forKeyPath: "otherValue", options: .new, context: nil)
object.someValue = "456" // success for `dynamic`
object.otherValue = "def" // failed to observe
object.removeObserver(self, forKeyPath: "someValue")
object.removeObserver(self, forKeyPath: "otherValue")
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("\(keyPath!) change to \(change![.newKey] as! String)")
}
}
Observer().ob()
/*
someValue change to 456
*/
05.where
定义泛型时, 或者关联类型(associatedtype)时, 会出现未定的类型, 参考泛型, 可以使用where对其进行限制
protocol MyProtocol where Element1 : NSNumber, Element2 == String {
associatedtype Element1
associatedtype Element2
func hello()
}
11212
06.00000000