閉包的介紹
閉包是自包含的函數(shù)代碼塊繁调、可以在代碼中被傳遞和使用。Swift中的閉包與C和OC中的代碼塊(Block)比較相似违崇!
閉包擁有三種形式:
- 全局函數(shù)是一個(gè)有名字但不會(huì)捕獲任何值的閉包
- 嵌套函數(shù)是一個(gè)有名字并可以捕獲其封閉函數(shù)域內(nèi)值的閉包
- 閉包表達(dá)式是一個(gè)利用輕量級(jí)語(yǔ)法縮寫(xiě)的可以捕獲其上下文中變量或常量值的匿名閉包
閉包表達(dá)式
閉包表達(dá)式一般形式:
{ (parameters) -> returnType in
statements
}
閉包的函數(shù)體部分由關(guān)鍵字in
引入豫喧。該關(guān)鍵字表示閉包的參數(shù)和返回值類(lèi)型定義已經(jīng)完成,閉包函數(shù)體即將開(kāi)始谦絮。
函數(shù)中閉包的定義
在函數(shù)中使用閉包题诵,定義方式如下:
import UIKit
class SomeTool: NSObject {
func loadData(callBack : @escaping (String) -> ()) {
DispatchQueue.global().async {
print("開(kāi)始異步加載...")
DispatchQueue.main.async {
print("主線程更新UI")
callBack("change UI")
}
}
}
}
注釋?zhuān)?/p>
- callBack為閉包參數(shù)名
-
(String) -> ()
為閉包類(lèi)型 -
@escaping
關(guān)鍵字表示閉包為“逃逸閉包” - Swift3.0中完全顛覆了原OC中得GCD寫(xiě)法,用法更加簡(jiǎn)潔
下面在控制器中調(diào)用上述含有閉包的函數(shù):代碼如下所示:
import UIKit
class ViewController: UIViewController {
var tool : SomeTool = SomeTool()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
tool.loadData { (info) in
print("\(info)")
}
}
}
//結(jié)果:
//開(kāi)始異步加載...
//主線程更新UI
//change UI
逃逸閉包
當(dāng)一個(gè)閉包作為參數(shù)傳到一個(gè)函數(shù)中层皱,但是這個(gè)閉包在函數(shù)返回之后才被執(zhí)行性锭,我們稱該閉包從函數(shù)中逃逸。當(dāng)你定義接受閉包作為參數(shù)的函數(shù)時(shí)叫胖,你可以在參數(shù)名之前標(biāo)注 @escaping草冈,用來(lái)指明這個(gè)閉包是允許“逃逸”出這個(gè)函數(shù)的。
在Swift3.0之前瓮增,閉包默認(rèn)時(shí)逃逸的怎棱,Swift3.0之后默認(rèn)是非逃逸的,所以在使用逃逸閉包時(shí)绷跑,需要添加關(guān)鍵字@escaping
拳恋,并且添加位置在閉包類(lèi)型名前而不是參數(shù)名前!
閉包循環(huán)引用的解決辦法
閉包的循環(huán)引用的解決辦法有三種方式:
- 方式一:
類(lèi)似OC中的寫(xiě)法你踩,設(shè)置weakSelf方式:
import UIKit
class ViewController: UIViewController {
var tool : SomeTool = SomeTool()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//1诅岩、解決閉包循環(huán)引用的方式一:
//1.弱引用self設(shè)置
weak var weakSelf = self
tool.loadData { (info) in
//1.1 弱引用self使用
/**weakSelf?.view:
如果前面的可選類(lèi)型讳苦,沒(méi)有值,后面所有代碼都不會(huì)執(zhí)行
若果前面的可選類(lèi)型吩谦,有值鸳谜,系統(tǒng)會(huì)自動(dòng)將weakSelf進(jìn)行解包,并且使用weakSelf
*/
weakSelf?.view.backgroundColor = UIColor.blue
print("\(info)")
}
}
}
- 方式二:
Swift中方式一的簡(jiǎn)便寫(xiě)法(推薦寫(xiě)法):
import UIKit
class ViewController: UIViewController {
var tool : SomeTool = SomeTool()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//2式廷、解決閉包循環(huán)引用的方式二:(推薦寫(xiě)法)
//2.方式一的簡(jiǎn)便寫(xiě)法
tool.loadData { [weak self] (info) in
self?.view.backgroundColor = UIColor.blue
print("\(info)")
}
}
}
- 方式三:
方式三相當(dāng)于OC中的__unsafe_unretained
方式:
import UIKit
class ViewController: UIViewController {
var tool : SomeTool = SomeTool()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//3咐扭、解決閉包循環(huán)引用的方式三:
//3.比較危險(xiǎn)
//相當(dāng)于OC中的__unsafe_unretained
//__unsafe_unretained:修飾的弱引用,當(dāng)指向的對(duì)象銷(xiāo)毀滑废,指針還會(huì)指向已經(jīng)銷(xiāo)毀的內(nèi)存地址(野指針)/訪問(wèn)僵尸對(duì)象
//__weak:修飾的弱引用蝗肪,如果指向的對(duì)象銷(xiāo)毀,那么指針會(huì)指向nil
tool.loadData { [unowned self] (info) in
self.view.backgroundColor = UIColor.blue
print("\(info)")
}
}
}
尾隨閉包
如果你需要將一個(gè)很長(zhǎng)的閉包表達(dá)式作為最后一個(gè)參數(shù)傳遞給函數(shù)蠕趁,可以使用尾隨閉包來(lái)增強(qiáng)函數(shù)的可讀性薛闪。尾隨閉包是一個(gè)書(shū)寫(xiě)在函數(shù)括號(hào)之后的閉包表達(dá)式,函數(shù)支持將其作為最后一個(gè)參數(shù)調(diào)用俺陋。
通俗的意思就是:函數(shù)的最后一個(gè)參數(shù)為閉包豁延,此閉包就為尾隨閉包,存在簡(jiǎn)便使用閉包的形式腊状!
上述閉包的用法诱咏,其實(shí)質(zhì)就是尾隨閉包!
繼續(xù)使用上述例子缴挖,來(lái)解釋一下尾隨閉包:
import UIKit
class ViewController: UIViewController {
var tool : SomeTool = SomeTool()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//1袋狞、尾隨閉包方式一:
tool.loadData{ (info) in
print("\(info)")
}
//2、尾隨閉包方式二:
tool.loadData (callBack: { (info) in
print("\(info)")
})
//3映屋、尾隨閉包方式三:
tool.loadData(){ (info) in
print("\(info)")
}
}
}
Zeb
參考地址:https://github.com/numbbbbb/the-swift-programming-language-in-chinese