先復(fù)習(xí)一下函數(shù)Swift-func
閉包可以定義一個(gè)函數(shù)
閉包可以定義一個(gè)函數(shù)
閉包可以定義一個(gè)函數(shù)
閉包概念:
- 一個(gè)函數(shù)和它所捕獲的變量/常量環(huán)境組合起來,稱為閉包
- 一般指定義在函數(shù)內(nèi)部的函數(shù)
- 一般它捕獲的是外層函數(shù)的局部變量/常量
演繹過程:
typealias Fn = (Int) -> Int
func getFn() -> Fn {
var num = 10
func plus(i: Int) -> Int {
num += I
return num
}
return plus//這是函數(shù)哦 不能是實(shí)現(xiàn)
return plus(I:)
}
var fnx = getFn()
print(fnx(1))
- 2層函數(shù) 外層函數(shù)
getFn返回值是函數(shù)類型 內(nèi)層函數(shù)plus也要返回函數(shù)類型 - plus函數(shù)和num形成了閉包
簡易一下程序
func getFn() -> Fn {
var num = 10
return {
num += $0
return num
}
}
類比一個(gè)類的實(shí)例對(duì)象
- 內(nèi)存在堆空間
- 捕獲的局部變量/常量就是對(duì)象的成員(存儲(chǔ)屬性)
- 組成閉包的函數(shù) 就是類內(nèi)部定義的方法
class Closure {
var num = 0
func plus(_ i:Int) -> Int {
num += I
return num
}
}
var cs1 = Closure()
print(cs1.plus(1))
閉包
Swift中,可以通過func定義一個(gè)函數(shù) 也可以通過閉包表達(dá)式定義一個(gè)函數(shù)
func add(_ v1: Int,_ v2: Int) -> Int {
v1 + v2
}
var fx = {
(v1: Int,v2: Int) -> Int in
return v1 + v2
}
print(fx(10,20))
print(fx)
print(add)
把實(shí)現(xiàn)帶著隨便測(cè)試
var fx1 = {
(v1: Int,v2: Int) -> Int in
return v1 + v2
}(10,10)
print(fx1)
- 上面打印
fx打印結(jié)果:(Function) - 上面打印
add打印結(jié)果:(Function) - 閉包類似add 然后調(diào)用它 傳入?yún)?shù)fx(10,20)

image.png
閉包作為參數(shù)(閉包簡寫真特么簡 其實(shí)不簡寫容易讀)
//exec定義
func exec(v1: Int,v2: Int,fn:(Int,Int) -> Int) {
print(fn(v1,v2))
}
實(shí)現(xiàn)exec方法
- 普通函數(shù)
var fn:(Int,Int)->Int = add
exec(v1: 10, v2: 10, fn: fn)
- 閉包
//寫全一點(diǎn)
exec(v1: 10, v2: 20, fn: {
(v1: Int,v2: Int) -> Int in
return v1 + v2
})
//省略return
exec(v1: 10, v2: 20, fn: {
(v1: Int,v2: Int) -> Int in
v1 + v2
})
//省略參數(shù)
exec(v1: 10, v2: 20, fn: {
v1,v2 -> Int in
v1 + v2
})
//省略返回值
exec(v1: 10, v2: 20, fn: {
v1,v2 in
v1 + v2
})
//下標(biāo)
exec(v1: 10, v2: 10, fn: {
$0 + $1
})
//一步到位了靠
exec(v1: 10, v2: 10, fn: +)
尾隨閉包
- 如果將一個(gè)很長的閉包表達(dá)式作為函數(shù)的最后一個(gè)實(shí)參,使用尾隨閉包可以增強(qiáng)函數(shù)的可讀性
- 尾隨閉包是一個(gè)被書寫在函數(shù)調(diào)用括號(hào)外面(后面)的閉包表達(dá)式
- 如果閉包表達(dá)式是函數(shù)的唯一實(shí)參,而且使用了尾隨閉包的語法,那就不需要在函數(shù)名后面寫圓括號(hào)
func exec1(fn:(Int,Int) -> Int) {
print(fn(1,2))
}
exec1(fn: {
(v1: Int,v2: Int) -> Int in
return v1 * v2
})
exec1{
(v1: Int,v2: Int) -> Int in
return v1 * v2
}
......下面同樣可以省略 自己搞吧
自動(dòng)閉包(語法真雞賊)
后面在搞吧 語法真特么難懂太簡易了
- @autoclosure 會(huì)自動(dòng)將20 封裝成閉包{20}
- @autoclosure 只支持 () -> T 格式的參數(shù)
- @autoclosure 并非只支持最后一個(gè)參數(shù)
- 空合并運(yùn)算符?? 使用了@autoclosure技術(shù)
- 有@autoclosure 無@autoclosure,構(gòu)成了函數(shù)重載
- 為了避免與期望沖突,使用了@autoclosure的地方最好明確注釋清楚,這個(gè)值會(huì)被推遲執(zhí)行
func getFirstPositive (_ v1: Int,_ v2: Int) -> Int {
return v1 > 0 ?v1 : v2
}
print(getFirstPositive(10, 20))
print(getFirstPositive(-2, 20))
print(getFirstPositive(0, -4))
//改成函數(shù)類型的參數(shù),可以讓v2延遲加載
func getFirstPositive(_ v1: Int,_ v2: () -> Int) -> Int? {
return v1 > 0 ? v1: v2()
}
print(getFirstPositive(-4, {20})!)
func getFirstPositive1(_ v1: Int,_ v2:@autoclosure () -> Int) -> Int? {
return v1 > 0 ? v1: v2()
}
print(getFirstPositive1(-4, 20)!)
參數(shù)修飾符保持一致
//如果返回值是函數(shù)類型,那么參數(shù)的修飾要保持統(tǒng)一
func total(_ num: Int) -> (inout Int) -> Void {
func plus(v: inout Int) {
v += num
}
return plus
}
var vvvv = 5
total(20)(&vvvv)
print(vvvv)
忽略參數(shù)(語法真雞賊)
func exec2(fn:(Int ,Int) -> Int) {
print(fn(1,2))
}
exec2{_,_ in 100}
練習(xí)
var functions:[() -> Int] = []
for i in 1...3 {
functions.append{I}
}
for i in functions {
print(i)
}
class Closure2 {
var i: Int
init(_ i: Int) {
self.i = I
}
func get() -> Int {
return I
}
}
var clses:[Closure2] = []
for i in 1...3 {
clses.append(Closure2(i))
}
for i in clses {
print(i.get())
}
補(bǔ)充案例
案例一:網(wǎng)絡(luò)請(qǐng)求 省略參數(shù) 逃逸閉包

image.png
Function types cannot have argument labels; use '_' before 'result'
從Swift3.0開始, 蘋果官方建議方法中函數(shù)類型的參數(shù)不要帶參數(shù)名稱, 尤其是不能帶外部參數(shù)名.
解決方案:
- 省略標(biāo)簽參數(shù)
- 這個(gè)閉包里面的標(biāo)簽參數(shù)是為了增加代碼可讀性
class func requestData(parameters: [String:Any]?,finishedCallBack:(_ result:Any)->()) {
finishedCallBack("回調(diào)請(qǐng)求內(nèi)容")
}
新的問題

image.png
逃逸閉包捕獲非逃逸閉包
captures:捕獲
Escaping:逃逸

image.png
語法小計(jì)
- 閉包實(shí)現(xiàn) 可以把參數(shù)省略
NetworkTools.requestData(url: requestUrl, method: .post, parameters: parameters) { response, status in
}
NetworkTools.requestData(url: requestUrl, method: .post, parameters: parameters) { (response, status) in
}