Xcode 10.x, Swift 4.2, 一些特别的关键词的使用

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

你可能感兴趣的:(iOS开发)