- 語(yǔ)法表達(dá)式
一般形式:{
(parameters) -> returnType in
statements
}
這里的參數(shù)(parameters)癣籽,可以是in-out(輸入輸出參數(shù)),但不能設(shè)定默認(rèn)值程拭。如果是可變參數(shù)定踱,必須放在最后一位,不然編譯器報(bào)錯(cuò)恃鞋。元組也可以作為參數(shù)或者返回值崖媚。
"in"關(guān)鍵字表示閉包的參數(shù)和返回值類型定義已經(jīng)完成,閉包函數(shù)體即將開(kāi)始恤浪。即由in引入函數(shù)
例子
//一般形式
let calAdd:(Int,Int)->(Int) = {
(a:Int,b:Int) -> Int in
return a + b
}
print(calAdd(100,150))
//Swift可以根據(jù)閉包上下文推斷參數(shù)和返回值的類型畅哑,所以上面的例子可以簡(jiǎn)化如下
let calAdd2:(Int,Int)->(Int) = {
a,b in //也可以寫(xiě)成(a,b) in
return a + b
}
print(calAdd2(150,100))
//上面省略了返回箭頭和參數(shù)及返回值類型,以及參數(shù)周圍的括號(hào)水由。當(dāng)然你也可以加括號(hào)荠呐,為了好看點(diǎn),看的清楚點(diǎn)砂客。(a,b)
//單行表達(dá)式閉包可以隱式返回泥张,如下,省略return
let calAdd3:(Int,Int)->(Int) = {(a,b) in a + b}
print(calAdd3(50,200))
//如果閉包沒(méi)有參數(shù)鞠值,可以直接省略“in”
let calAdd4:()->Int = {return 100 + 150}
print("....\(calAdd4())")
//這個(gè)寫(xiě)法媚创,我隨便寫(xiě)的。打印出“我是250”
//這個(gè)是既沒(méi)有參數(shù)也沒(méi)返回值齿诉,所以把return和in都省略了
let calAdd5:()->Void = {print("我是250")}
calAdd5()
- 歸納
閉包類型是由參數(shù)類型和返回值類型決定筝野,和函數(shù)是一樣的。比如上面前三種寫(xiě)法的閉包的閉包類型就是(Int,Int)->(Int),后面的類型分別是()->Int和()->Void粤剧。分析下上面的代碼:let calAdd:(add類型)歇竟。這里的add類型就是閉包類型 (Int,Int)->(Int)。意思就是聲明一個(gè)calAdd常量抵恋,其類型是個(gè)閉包類型焕议。
"="右邊是一個(gè)代碼塊,即閉包的具體實(shí)現(xiàn)弧关,相當(dāng)于給左邊的add常量賦值盅安。兄弟們唤锉,是不是感覺(jué)很熟悉了,有點(diǎn)像OC中的block代碼塊别瞭。 - 起別名
也可以關(guān)鍵字“typealias”先聲明一個(gè)閉包數(shù)據(jù)類型窿祥。類似于OC中的typedef起別名
typealias AddBlock = (Int, Int) -> (Int)
let Add:AddBlock = {
(c,d) in
return c + d
}
let Result = Add(100,150)
print("Result = \(Result)")
- 尾隨閉包
若將閉包作為函數(shù)最后一個(gè)參數(shù),可以省略參數(shù)標(biāo)簽,然后將閉包表達(dá)式寫(xiě)在函數(shù)調(diào)用括號(hào)后面
func testFunction(testBlock: ()->Void){
//這里需要傳進(jìn)來(lái)的閉包類型是無(wú)參數(shù)和無(wú)返回值的
testBlock()
}
//正常寫(xiě)法
testFunction(testBlock: {
print("正常寫(xiě)法")
})
//尾隨閉包寫(xiě)法
testFunction(){
print("尾隨閉包寫(xiě)法")
}
//也可以把括號(hào)去掉蝙寨,也是尾隨閉包寫(xiě)法晒衩。推薦寫(xiě)法
testFunction {
print("去掉括號(hào)的尾隨閉包寫(xiě)法")
}
- 值捕獲
閉包可以在其被定義的上下文中捕獲常量或變量。Swift中墙歪,可以捕獲值的閉包的最簡(jiǎn)單形式是嵌套函數(shù)听系,也就是定義在其他函數(shù)的函數(shù)體內(nèi)的函數(shù)。
func captureValue(sums amount:Int) -> ()->Int{
var total = 0
func incrementer()->Int{
total += amount
return total
}
return incrementer
}
print(captureValue(sums: 10)())
print(captureValue(sums: 10)())
print(captureValue(sums: 10)())
//打印"10 10 10"
這里沒(méi)有值捕獲的原因是虹菲,沒(méi)有去用一個(gè)常量或變量去引用函數(shù)靠胜,所以每次使用的函數(shù)都是新的。有點(diǎn)類似于OC中的匿名對(duì)象毕源。
let referenceFunc = captureValue(sums: 10)
print(referenceFunc())
print(referenceFunc())
print(referenceFunc())
//打印"10 20 30"
這里值捕獲了浪漠,是因?yàn)楹瘮?shù)被引用了,所以沒(méi)有立即釋放掉脑豹。所以函數(shù)體內(nèi)的值可以被捕獲
- 閉包形式
func captureValue2(sums amount:Int) -> ()->Int{
var total = 0
let AddBlock:()->Int = {
total += amount
return total
}
return AddBlock
}
let testBlock = captureValue2(sums: 100)
print(testBlock())
print(testBlock())
print(testBlock())
由上面的例子都可以證得郑藏,函數(shù)和閉包都是引用類型。
- 逃逸閉包
當(dāng)一個(gè)閉包作為參數(shù)傳到一個(gè)函數(shù)中瘩欺,需要這個(gè)閉包在函數(shù)返回之后才被執(zhí)行,我們就稱該閉包從函數(shù)種逃逸拌牲。一般如果閉包在函數(shù)體內(nèi)涉及到異步操作俱饿,但函數(shù)卻是很快就會(huì)執(zhí)行完畢并返回的,閉包必須要逃逸掉塌忽,以便異步操作的回調(diào)拍埠。
逃逸閉包一般用于異步函數(shù)的回調(diào),比如網(wǎng)絡(luò)請(qǐng)求成功的回調(diào)和失敗的回調(diào)土居。語(yǔ)法:在函數(shù)的閉包行參前加關(guān)鍵字“@escaping”枣购。
//例1
func doSomething(some: @escaping () -> Void){
//延時(shí)操作,注意這里的單位是秒
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
//1秒后操作
some()
}
print("函數(shù)體")
}
doSomething {
print("逃逸閉包")
}
//例2
var comletionHandle: ()->String = {"約嗎?"}
func doSomething2(some: @escaping ()->String){
comletionHandle = some
}
doSomething2 {
return "叔叔擦耀,我們不約"
}
print(comletionHandle())
//將一個(gè)閉包標(biāo)記為@escaping意味著你必須在閉包中顯式的引用self棉圈。
//其實(shí)@escaping和self都是在提醒你,這是一個(gè)逃逸閉包眷蜓,
//別誤操作導(dǎo)致了循環(huán)引用分瘾!而非逃逸包可以隱式引用self。
//例子如下
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 }
}
}
- 自動(dòng)閉包
顧名思義吁系,自動(dòng)閉包是一種自動(dòng)創(chuàng)建的閉包德召,封裝一堆表達(dá)式在自動(dòng)閉包中白魂,然后將自動(dòng)閉包作為參數(shù)傳給函數(shù)。而自動(dòng)閉包是不接受任何參數(shù)的上岗,但可以返回自動(dòng)閉包中表達(dá)式產(chǎn)生的值福荸。
自動(dòng)閉包讓你能夠延遲求值,直到調(diào)用這個(gè)閉包肴掷,閉包代碼塊才會(huì)被執(zhí)行逞姿。說(shuō)白了,就是語(yǔ)法簡(jiǎn)潔了捆等,有點(diǎn)懶加載的意思滞造。
var array = ["I","have","a","apple"]
print(array.count)
//打印出"4"
let removeBlock = {array.remove(at: 3)}//測(cè)試了下,這里代碼超過(guò)一行栋烤,返回值失效谒养。
print(array.count)
//打印出"4"
print("執(zhí)行代碼塊移除\(removeBlock())")
//打印出"執(zhí)行代碼塊移除apple" 這里自動(dòng)閉包返回了apple值
print(array.count)
//打印出"3"
文章轉(zhuǎn)載自:http://www.cocoachina.com/ios/20161201/18250.html