前面簡單的說了Block可以作為屬性,方法參數(shù)和方法返回使用。這里更加詳細的介紹一下Block,并且結合實際情況對Block進行使用。
-
什么是Block
Block又稱作是閉包、塊。這兩種概念又是什么呢?
Block是一種函數(shù),這種函數(shù)在別的函數(shù)內部存在,并且可以使用其所在函數(shù)內的局部變量。
希望這樣的解釋稍微容易理解一些。
-
Block的寫法和調用
在xcode里面,可以輸入inlineBlock獲取Block的基本寫法:
returnType(^blockName)(parameterTypes) = ^(parameters) {
statements
};
調用的時候,直接使用名字加一對小括號就可以了:
blockName ();
但是這個地方有一個坑,它省略了等號后面的返回類型。一般情況下沒有什么問題,但是如果返回的是nil,編譯器就會報錯。如下圖:
我們只要在等號后面加上對應的返回值,即可編譯通過。
所以嚴格意義上,等號后面也應該有返回類型。
-
Block在實際開發(fā)中的使用
我們先定義一個類,叫Person。
1. block作為屬性
給我們之前定義的person類增加一個屬性:
//對Block的修飾:MRC用copy,ARC用Strong
@property (nonatomic, strong) void(^eat)(void);
然后測試一下:
Person *p = [Person new];
//Block作為屬性
p.eat = ^{
NSLog(@"吃飯了!");
};
_p = p;
調用:
_p.eat();
控制臺輸出:
吃飯了
2. block作為方法參數(shù)
還是給之前的Person類增加一個新的方法:
.h
//Block作為參數(shù)時,blockname不需要寫在^后面,直接寫在括號后面
- (void)eatWith:(void(^)(void))block;
.m
- (void)eatWith:(void (^)(void))block {
block();
}
測試代碼:
//Block作為方法參數(shù)
[_p eatWith:^{
NSLog(@"吃了一頓大餐!");
}];
控制臺輸出:
吃了一頓大餐
3. block作為方法的返回值
.h
//Block作為返回值
- (void(^)(int i))run;
.m
- (void(^)(int i))run {
return ^(int i){
NSLog(@"我走了%d米",i);
};
}
測試調用:
void(^block)(int i)= _p.run;
block(1);
//上面這兩行代碼可以合并為下面這一行
_p.run(1);//有沒有發(fā)現(xiàn)這個調用和block作為屬性時是一樣的,下面會繼續(xù)分析
控制臺輸出:
我走了1米
-
關于Block用法的引申思考
在前面,我們簡單的運用了block的幾種使用場景,但是在使用過程中,逐漸體會到了block的神奇。
1. 函數(shù)式編程
把Block當做函數(shù)的參數(shù),可以把我們的邏輯和函數(shù)放在調用時候的block里面,而不是方法內部。這樣會讓我們在寫代碼的時候,把相關的邏輯都放在一起,提高了開發(fā)效率和程序的可讀性。這其實就是函數(shù)式編程思想。函數(shù)式編程在很多第三方框架中都有明顯的體現(xiàn),比如說我們頻繁使用的AFNetWorking、Masonry等。
我們這里對Masonry框架進行一些簡單的分析。
Masonry是一個輕量級的布局框架。這是一個非常簡單并且常見的Masonry框架的運用:
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(superview).with.insets(padding);
}];
2.鏈式調用
外面的block就是一個函數(shù)式編程的體現(xiàn),但是我們看到它在Block內部調用方法的時候,不是像我們使用常規(guī)的OC語言一樣,而是不斷地使用點語法調用,極大的精簡了代碼量,同時也擁有很好的可讀性,使用起來極其方便。這種方式叫鏈式調用。
那么結合我們剛剛對block的使用,鏈式調用時怎么實現(xiàn)的呢?
- 后面帶括號,說明方法的返回值是一個Block。
- 調用方法肯定是對象才可以進行調用,說明Block的返回值是一個對象。
- 點語法則說明這個方法沒有參數(shù)。
結合以上三點思考,我們可以得出一個結論,一個沒有參數(shù)&有返回值&返回值是Block&Block的返回值是方法的調用者的方法,就可以實現(xiàn)鏈式調用:
.h
//鏈式調用方法
- (Person *(^)(NSString *city))travel;
.m
- (Person *(^)(NSString *))travel {
return ^(NSString *city){
NSLog(@"我去了%@",city);
return self;
};
}
測試一下:
//鏈式調用
_p.travel(@"重慶").travel(@"北京");
控制臺輸出:
我去了重慶
我去了北京
這樣我們就實現(xiàn)了鏈式調用。
函數(shù)式編程和鏈式調用就是Masonry用到的主要思想。我用這兩種思想,寫了一個簡單的計算器。可以通過鏈式調用的方式做運算,代碼和之前的demo都放在git上點擊前往。