為什么題目是“Block的使用你看我啊”,而不是牛逼哄哄的“Block你看我就夠了”羞反,原因是本文并不會講解Block在C++中的實(shí)現(xiàn)部分观游,而是停留在OC語言中稽屏。主要講訴一些語法和使用奖慌。
(如果本文中有講述不對或者不準(zhǔn)確的地方歡迎大家提出來)
1抛虫、Block是什么?
- 匿名函數(shù)
- 截獲自動變量
2简僧、Block語法建椰。
3、Block類型變量岛马。
4棉姐、Block的用途。
- 作為函數(shù)參數(shù)
- 反向傳值
- 循環(huán)引用
(delegate差不多作用啦逆,但是顯得更加簡潔)
首先就是Block是什么伞矩?用一句話來概括就是帶有自動變量的匿名函數(shù)。
那么我們解釋清楚了什么是“匿名函數(shù)”夏志,什么是“自動變量”乃坤,那么相信大家大概就對Block有了一個(gè)大概的認(rèn)識。
-
匿名函數(shù)
匿名函數(shù)顧名思義就是不帶名字的函數(shù)沟蔑,在C語言中不允許這樣的方法存在侥袜,而在OC中的Block則可以用指針來直接調(diào)用一個(gè)函數(shù),但雖說如此我們還是需要知道指針的名稱溉贿。(關(guān)于這點(diǎn)枫吧,額~~我們還是不要糾結(jié)的比較好∮钌~九杂!~~) -
自動變量
自動變量在Block中的具體表現(xiàn)就是截獲自動變量,來看下面這一段代碼:
int b = 0;
void (^blo)() = ^{
NSLog(@"Input:b=%d",b);
};
b = 3;
blo();
/**
* Input:b=0
*/
雖然我們在調(diào)用blo之前改變了b的值宣蠕,但是輸出的還是Block編譯時(shí)候b的值例隆,所以截獲瞬間自動變量就是:在Block中會保存變量的值,而不會隨變量的值的改變而改變抢蚀。
我們再來看一段代碼
int b = 0;
void (^blo)() = ^{
b = 3;
};
這段代碼編譯出錯(cuò)镀层,編譯器提示的大概就是不能在Block中改變變量的值。因?yàn)樵?strong>Block中截獲了變量的瞬間值以后就不能再改變變量的值皿曲,如果想要在Block中改變變量的值唱逢,那么我們只需要在變量聲明的時(shí)候加上__Block修飾符,像這樣:
__block int b = 0;
void (^blo)() = ^{
b = 3;
};
然而這樣的情況又是允許的:
NSMutableArray *array = [[NSMutableArray alloc]init];
void (^blo)() = ^{
[array addObject:@"Obj"];
};
為什么呢屋休,因?yàn)槲覀冎皇菍孬@的變量進(jìn)行了操作坞古,而沒有進(jìn)行賦值,所以對于截獲變量劫樟,可以進(jìn)行操作而不可以進(jìn)行賦值痪枫。
還有一點(diǎn)需要注意织堂,在Block中不可以對C語言數(shù)組進(jìn)行操作,原因是:~~~不支持奶陈。易阳。。吃粒。
結(jié)合匿名函數(shù)和截獲自動變量的特性潦俺,Block可以做很多事情,我們下面在看声搁。
我們來具體看一下Block語法的書寫,我們首先來看一個(gè)完整的Block:
^ NSString *(NSString *a,NSString *b){
return a;
};
我們來分別解釋下每一個(gè)部分都是什么東西:
- “^”這個(gè)符號表示這是一個(gè)Block捕发;
- NSString *表示返回值疏旨。
- (NSString *a,NSString *b)這個(gè)括號中是Block的參數(shù),語法和C語言類似扎酷。
其實(shí)我們可以省略Block的返回值檐涝,像這樣寫:
^ (NSString *a,NSString *b){
return a;
};
這樣寫和上面那種寫法是一模一樣的,其實(shí)如果沒有參數(shù)列表我們甚至可以省略參數(shù)列表法挨,像這樣:
^ {
NSLog(@"我沒有參數(shù)列表");
};
如果把這段代碼寫完整谁榜,那么就是這樣的:
^void(void) {
NSLog(@"我沒有參數(shù)列表");
};
為什么需要Block變量?我們可以這樣理解凡纳,我們通過這個(gè)Block變量來獲取Block的指針窃植,然后通過這個(gè)指針就可以來使用Block函數(shù)。我們先來看一下如何聲明一個(gè)Block變量
int (^Blo)(NSString *s1,NSString *s2);
對照前面的Block函數(shù)荐糜,我們可以比較容易的理解各個(gè)部分的含義:
他們分別是:
- 返回值
- 變量名
- 參數(shù)列表
好的巷怜,然后我們用上面講到的Block語法來對這個(gè)Block變量進(jìn)行賦值:
int (^Blo)(NSString *s1,NSString *s2);
Blo = ^(NSString *s1,NSString *s2){
return 1;
};
然后我們就可以將這個(gè)Block變量當(dāng)作C語言函數(shù)來使用了。
那么Block到底怎么用呢暴氏?
Block能夠當(dāng)作函數(shù)參數(shù)延塑,首先我們聲明一個(gè)Block類型變量 ,并加上typedef修飾符答渔,像這樣:
typedef void(^Blo)(NSString *s1,UIColor *c);
這樣我們就可以使用Blo來表示這個(gè)Block关带,然后我就可以將Blo加入到函數(shù)參數(shù)中,我們來聲明一個(gè)函數(shù):
-(void)func:(Blo)BlockPra{
BlockPra(@"Str",[UIColor redColor]);
}
然后我們可以這樣使用這個(gè)函數(shù):
[self func:^(NSString *s1, UIColor *c) {
NSLog(@"%@",s1);
self.view.backgroundColor = c;
}];
是不是覺得十分眼熟沼撕,平時(shí)使用的許多回調(diào)當(dāng)中大多都是這樣的形式宋雏,可能其中其較多的就是網(wǎng)絡(luò)回調(diào)了,我們只需要調(diào)用方法务豺,然后在回調(diào)當(dāng)中就可以對結(jié)果進(jìn)行操作好芭,很多蘋果自己寫的API都是使用了這樣的方法,這樣做的好處就是形式上十份簡潔冲呢,當(dāng)然像這種地方你使用delegate肯定也是可以的舍败,但是表現(xiàn)上就沒有Block那么簡潔,使用起來也沒有Block那么方便。
除此之外邻薯,Block還可以用來作為控制器之間的一個(gè)通信裙戏。
前面我們已經(jīng)知道Blcok是一個(gè)匿名函數(shù),同時(shí)也是一個(gè)指針厕诡,那么使用Block就可以彌補(bǔ)在iOS中函數(shù)傳遞的功能累榜。通常是這么用的:
頁面B的.h文件中定義了這樣一個(gè)Block執(zhí)政,然后聲明了一個(gè)變量灵嫌,像這樣:
typedef void(^Blo)(NSString *s1,UIColor *c);
@property (nonatomic, copy) Blo block;
然后我們在頁面A當(dāng)中有這么一段代碼:
ViewController *b = [[ViewController alloc]init];
__weak ViewController *wself = self;
b.block = ^(NSString *s1,UIColor *c){
NSLog(@"%@",s1);
wself.view.backgroundColor = c;
};
[self.navigationController pushViewController:b animated:true];
然后在頁面B的任意地方我們調(diào)用block變量壹罚,像這樣:
self.block(@"str",[UIColor redColor]);
都會在A頁面中調(diào)用B頁面?zhèn)鬟^來的參數(shù),在A頁面進(jìn)行操作寿羞,對控制器A進(jìn)行改變猖凛,這樣的做法通常用做 控制器 反向傳值。
在這里有一點(diǎn)需要注意就是Block的使用引起的循環(huán)引用绪穆。如果在Block中使用附有__strong修飾符的對象類型自動變量辨泳,那么當(dāng)Block從棧復(fù)制到堆時(shí),改對象為Block所有玖院。這樣容易引起循環(huán)引用菠红,從而發(fā)生內(nèi)存泄漏,然而我們只需要保證當(dāng)前控制器也就是self在需要釋放的時(shí)候正確釋放就可以难菌,所以我們再來看上面那段代碼:
__weak ViewController *wself = self;
我們定義一個(gè)wself變量并加上__weak修飾符试溯,在Block代碼塊中,所有需要self的地方都用wself來替代郊酒。這樣就不會增加引用計(jì)數(shù)耍共,所以Block持有self對象也就不會造成循環(huán)引用,從而造成內(nèi)存泄漏猎塞。
不管是將Block當(dāng)作函數(shù)參數(shù)试读,還是用來反向傳值,其實(shí)都是對Block的本質(zhì)荠耽,也就是“帶有自動變量的匿名函數(shù)”的兩個(gè)修飾钩骇,“帶有自動變量”、“匿名函數(shù)”這兩個(gè)特性 的應(yīng)用铝量。
總結(jié)一下Block到底是什么倘屹、用來干什么:
- C++中的Struct(本文未提到)。
- 用來彌補(bǔ)iOS中函數(shù)傳遞的功能慢叨。
- 他是一段代碼塊的內(nèi)存的指針纽匙。
- 和delegate一樣的功能,但是顯的更加簡潔拍谐。
差不多就這樣吧烛缔,自我感覺本文是有邏輯的馏段,但是部分講解可能不是特別到位谐宙,覺得還不錯(cuò)的請關(guān)注本人疼电。