閉包介紹
Swift閉包和Objective-C中的Block很類似,是一段自包含的函數(shù)代碼塊,可以在代碼中使用和傳遞。相當(dāng)于一個匿名函數(shù)。
函數(shù):是一個有名字的閉包。
普通函數(shù):是一個有名字但不會捕獲任何值的閉包。
嵌套函數(shù):是一個有名字并可以捕獲其封閉函數(shù)域內(nèi)值的閉包。
閉包格式
閉包表達(dá)式語法有如下的一般形式:
{ (parameters) -> returnType in
statements
}
閉包使用、尾隨閉包、閉包簡寫格式
// 以下閉包以Array的sorted函數(shù)為例
func testClosure() {
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backward(_ str1: String, _ str2: String) -> Bool {
return str1 > str2
}
// sorted函數(shù)的參數(shù)是一個閉包,下面?zhèn)髁艘粋€方法名,由此說明:嵌套函數(shù)是一個有名字但并可以捕獲其封閉函數(shù)域內(nèi)值的閉包
var reversedNames = names.sorted(by: backward)
// 普通閉包格式:(參數(shù): 參數(shù)類型,...) -> 返回值類型 in ...
reversedNames = names.sorted(by: {(_ str1: String, _ str2: String) -> Bool in return str1 > str2})
// 根據(jù)Swift的類型推斷,參數(shù)類型及參數(shù)括號可以去掉,返回值類型可以去掉
reversedNames = names.sorted(by: {str1, str2 in return str1 > str2})
// 單行表達(dá)式:可以去掉return
reversedNames = names.sorted(by: {str1, str2 in str1 > str2})
// 使用參數(shù)名縮寫:參數(shù)和in也可以去掉
reversedNames = names.sorted(by: {$0 > $1})
// 使用運(yùn)算符:因?yàn)镾wift中為字符串重載了大于號小于號
reversedNames = names.sorted(by: >)
// 使用尾隨閉包:前提是閉包必須是函數(shù)的最后一個參數(shù)
reversedNames = names.sorted() {$0 < $1}
// 使用尾隨閉包:閉包是函數(shù)唯一參數(shù)時,可以省掉參數(shù)括號
reversedNames = names.sorted {$0 < $1}
print(reversedNames)
}
閉包值捕獲,閉包是引用類型
先貼代碼:
// 值捕獲示例:下面嵌套函數(shù)incrementer本身沒有參數(shù),它卻捕獲了外圍的參數(shù)runningTotal和amount
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
// 調(diào)用
let makeIncrementByTen = makeIncrementer(forIncrement: 10)
var ret = makeIncrementByTen()
print("ret= \(ret)")// ret= 10
ret = makeIncrementByTen()
print("ret= \(ret)")// ret= 20
ret = makeIncrementByTen()
print("ret= \(ret)")// ret= 30
let makeIncrementBySeven = makeIncrementer(forIncrement: 7)
ret = makeIncrementBySeven()
print("ret= \(ret)")// ret= 7
ret = makeIncrementByTen()
print("ret= \(ret)")// ret= 40
// 上面的同一個閉包連續(xù)調(diào)用,值會遞增原因:閉包是引用類型,同一個閉包捕獲的變量并沒有釋放
逃逸閉包
逃逸閉包概念:當(dāng)一個閉包作為參數(shù)傳到一個函數(shù)中,但是這個閉包在函數(shù)返回之后才被執(zhí)行,我們稱該閉包從函數(shù)中逃逸。逃逸閉包多用來做函數(shù)回調(diào),與Objective-C里的Block有異曲同工之妙。
代碼示例:
// 逃逸閉包示例:下面的閉包被方法外的數(shù)組引用,也就意味著,這個閉包在函數(shù)執(zhí)行完后還可能被調(diào)用,所以必須使用逃逸閉包,不然編譯不過去
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
// 非逃逸閉包
func someFunctionWithNoneEscapingClosure(closure: () -> Void) {
closure()
}
var x = 10
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// 逃逸閉包
someFunctionWithEscapingClosure {
// 注意:逃逸閉包類必須顯式的引用self,
self.x = 100
}
someFunctionWithNoneEscapingClosure {
x = 200
}
print("x= \(x)")// x= 200
completionHandlers.first?()
print("x= \(x)")// x= 100
}
自動閉包
自動閉包:閉包作為參數(shù)傳遞給函數(shù)時,可以將閉包定義為自動閉包(使用關(guān)鍵字@autoclosure)。這樣傳遞參數(shù)時,可以直接傳遞一段代碼(或者一個變量、表達(dá)式),系統(tǒng)會自動將這段代碼轉(zhuǎn)化成閉包。需要注意:過度使用 autoclosures 會讓你的代碼變得難以理解。這里不貼代碼了。