關(guān)于block
一. 什么是block?
Block是帶有局部變量的匿名函數(shù). 等等,這句話是不是比較拗口,有點(diǎn)難理解對(duì)不對(duì),這樣,你就記住,Block就是一個(gè)代碼塊,用個(gè)大括號(hào)包6起來(lái),它預(yù)先準(zhǔn)備好,但是暫時(shí)不執(zhí)行,要再需要的時(shí)候在調(diào)用執(zhí)行. 就這么簡(jiǎn)單. 那么問(wèn)題來(lái)了,既然它是一個(gè)被包起來(lái)的代碼塊, 那么它也是一種數(shù)據(jù)類型,也就可以當(dāng)做參數(shù)來(lái)傳遞,也就可以定義成屬性.
example: 舉一個(gè)生活中的簡(jiǎn)單例子,可以幫助我們來(lái)理解block.
大家都聽(tīng)說(shuō)”錦囊妙計(jì)”這個(gè)典故,block就是那個(gè)錦囊,你把錦囊揣在口袋里,遇到麻煩的時(shí)候,不知道怎么辦了,需要用到錦囊的時(shí)候,再打開(kāi),按照錦囊里面寫的內(nèi)容去做.來(lái)解決麻煩.
二, block的用途
那么我們?cè)谀切┑胤娇梢杂玫絙lock呢? 其使用場(chǎng)景與代理是類似的,但是比代理要的代碼量要少很多,也相對(duì)簡(jiǎn)單些
A ,可以用于自定義視圖的反向傳值
B, modal/POP 控制器的反向傳值
C, 異步方法執(zhí)行完畢后的反向傳值
三, block的傳值的方法:
返現(xiàn)傳遞的數(shù)據(jù)通過(guò)block的參數(shù)來(lái)傳遞,一般稱為回調(diào)
四, 代碼(反向傳值)
Demo: DewViewController得到數(shù)據(jù)之后回傳值給ViewController
- 第一步:在DewViewController中定義一個(gè)block類型的數(shù)據(jù)
@property (nonatomic,copy) void(^block)(NSString *nameText);
- 第二步: 在ViewController中定義一個(gè)等待執(zhí)行的代碼塊,
- 第三步: 獲取目標(biāo)控制器,將代碼塊丟給目標(biāo)控制器的屬性
//監(jiān)聽(tīng)控制器的跳轉(zhuǎn)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
//1.定義好一個(gè)等待執(zhí)行的代碼塊
void (^block)() = ^(NSString *nameText){
self.nameLable.text = nameText;
};
//2. 獲取目標(biāo)控制器
DewViewController *detailVC = segue.destinationViewController;
//3. 在控制器跳轉(zhuǎn)的時(shí)候,把blocke傳入到DewViewController
if (detailVC != nil){
detailVC.block = block;
}
}
- 第四步: 在DewViewController中的按鈕點(diǎn)擊方法中,把textField中獲取的值交給屬性block回傳給ViewController,代碼塊這個(gè)時(shí)候開(kāi)始執(zhí)行,這樣ViewController中的label就獲取到了DewViewController的值
- (IBAction)saveAction:(id)sender {
if(self.nameTextField != nil){
//調(diào)用block,傳入?yún)?shù)
self.block(self.nameTextField.text);
}
[self.navigationController popViewControllerAnimated:YES];
}
五, 需要注意的是: 循環(huán)引用問(wèn)題
造成循環(huán)引用問(wèn)題的原因: 在定義一個(gè)block類型的屬性是,使用copy,表示'self' 強(qiáng)引用了block,那如果在block中強(qiáng)引用了'self',就會(huì)造成循環(huán)引用
解決辦法: 在方法中使用 __weak
__weak typeof(self) weakSelf = self;
關(guān)于swift閉包
一, 所謂閉包,其定義和用法和OC中的block非常類似.可以這樣理解: block能完成的功能,閉包都能做到. 但是不管怎么樣,還是有點(diǎn)區(qū)別的
二, Demo-虛擬下載完電影之后更新UI,用閉包回調(diào),實(shí)現(xiàn)反向傳值
a. 定義一個(gè)變量 變量名是callBack, 類型是閉包
var callBack: ((String)->())?
b. 用閉包作為參數(shù)傳遞
//下載電影
func downloadMovie (callBack: @escaping (String) -> ()) {
self.callBack = callBack
DispatchQueue.global().async(execute: {})
//模擬異步加載數(shù)據(jù)
DispatchQueue.global().async {
Thread.sleep(forTimeInterval: 2)
let movieName = "模仿游戲"
//完成后,在主線程更新UI
DispatchQueue.main.async(execute: {
//閉用閉包刷新UI
callBack(movieName)
})
}
}
c. 在viewDidLoad中調(diào)用downloadMove方法,傳入?yún)?shù):閉包
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
//添加label
let label = customLabel(title: "正在下載...")
view.addSubview(label)
//調(diào)用下載電影的方法,傳入?yún)?shù),就可以直接調(diào)用下面大括號(hào)里面的代碼-(尾隨閉包)
downloadMovie {
[weak self](movieName: String) in
label.text = "\(movieName), 下載完成!"
print(self!)
}
}