闭包表达式语法

<aside> 🦊 闭包表达式语法中的参数可以是输入输出参数,也可以是可变参数,但不能是默认参数,元组既可以作为闭包表达式语法中的参数,也可以作为返回值。

</aside>

// 函数到闭包的演化:
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

// -----> 函数:
func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}
var reversedNames = names.sorted(by: backward)
// reversedNames 为 ["Ewa", "Daniella", "Chris", "Barry", "Alex"]

// -----> 闭包:
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

// -----> 单行闭包:
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )

// -----> 省略参数返回值类型闭包:
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )

// -----> 单表达式隐式返回闭包:
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

// -----> 参数名称缩写闭包:
reversedNames = names.sorted(by: { $0 > $1 } )

// -----> 运算符方法:
reversedNames = names.sorted(by: >)

// -----> 尾随闭包:
reversedNames = names.sorted() { $0 > $1 }

// -----> 单一参数省略括号尾随闭包:
reversedNames = names.sorted { $0 > $1 }

尾随闭包

<aside> 🏄‍♀️ 如果函数参数中有多个尾随闭包,只有第一个可以省略参数标签,其余的尾随闭包需写出参数标签。

</aside>

func loadPicture(from server: Server, completion: (Picture) -> Void, onFailure:() -> Void) {
    if let picture = download("photo.jpg", from: server) {
        completion(picture)
    } else {
        onFailure()
    }
}
loadPicture(from: someServer) { picture in
    someView.currentPicture = picture
} onFailure: {
    print("Couldn't download the next picture")
}

逃逸闭包

逃逸闭包可以延迟闭包调用的时间,比如将一个闭包作为参数传递给一个函数,但是函数返回之后闭包才会被执行,这时需要指明该闭包允许“逃逸”出这个函数。

<aside> 👼 逃逸闭包中使用 self 需要显式调用,以此来检查并避免循环引用。

</aside>

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}
func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
}

class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { self.x = 100 }
        someFunctionWithNonescapingClosure { x = 200 }
    }
}

let instance = SomeClass()
instance.doSomething()
print(instance.x)
// 打印出“200”

completionHandlers.first?()
print(instance.x)
// 打印出“100”

<aside> 🧝‍♀️ 逃逸闭包不能捕获一个指向结构体或枚举中对 self 的可变引用,因为结构体或枚举是值类型,所以被外部使用时不能为可变的。

</aside>

struct SomeStruct {
    var x = 10
    mutating func doSomething() {
        someFunctionWithNonescapingClosure { x = 200 } // Ok
        someFunctionWithEscapingClosure { x = 100 } // Error
    }
}

自动闭包

自动闭包是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。这种闭包不接受任何参数,当它被调用时,会返回被包装在其中的表达式的值。这种便利语法让你可以省略闭包的花括号,用一个普通的表达式来代替显式的闭包,且自动闭包能让你延迟求值。

var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
// 打印出“5”

let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
// 打印出“5”

print("Now serving \\(customerProvider())!")
// 打印出“Now serving Chris!”
print(customersInLine.count)
// 打印出“4”