1.是什麼?函數
一種特殊的數據類型優化
2.有什麼用?atom
用於保存代碼塊spa
3.怎麼用?code
>1.聲明block的快捷鍵:對象
inlineBlockblog
>2.block的聲明:內存
<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) { <#statements#> };
>3.聲明/初始化/調用it
//聲明 void(^myBlock1)();//無參無反 int(^myBlock2)();//無參有反 void(^myBlock3)(int);//有參無反 int(^myBlock4)(int,int);//有參有反 //初始化 myBlock1 = ^() { NSLog(@"無參無反"); }; myBlock2 = ^() { return 3; }; myBlock3 = ^(int a) { NSLog(@"%d",a); }; myBlock4 = ^(int a,int b) { return a + b; }; //調用 myBlock1(); int num = myBlock2(); myBlock3(3); int sum = myBlock4(3,4);
>4.給block起別名event
返回值類型 (^別名)(參數);
例:
typedef void(^myBlock)();//給第一個無參無反的block起別名myBlock,myBlock就稱爲一種數據類型
使用:
myBlock block1 = ^(){ NSLog(@"聲明和定義不一樣,聲明僅僅是聲明一個變量(開闢一塊內存空間),並不初始化,定義包含了初始化,像這樣便是聲明的同時初始化了"); };
像這樣僅僅是聲明瞭一個myBlock類型的變量:
myBlock block2;
myBlock block3;
myBlock block4;
由於block是一種數據類型,所以數據類型所具備的所用特性block都具備,能夠聲明變量;做爲參數;做爲返回值;
>5.block做爲函數參數
>例一:
typedef int(^myBlock2)(); typedef int(^myBlock3)(int);
int sum(myBlock2 m,myBlock3 n,int a)//a爲myBlock3須要的參數 { // int num1 = m(); // int num2 = n(a); // return num1 + num2; return m() + n(a); }
//block做爲函數參數 myBlock2 m = ^(){ return 10; }; myBlock3 n = ^(int a) { return a; }; int num = sum(m, n, 10); NSLog(@"%d",num);//輸出20;
此種方式並不經常使用.經常使用的情景是:好比有三個函數,開頭和結尾部分執行的代碼同樣,中間有部分代碼不一樣,那麼就能夠將中間部分抽取爲block,將三個函數變爲一個,調用三次該函數,傳入不一樣的block便可.
>例二:
void test1() { NSLog(@"AAAAAAAAAAAAAAAAAAAA"); NSLog(@"星期天,今天去哪兒浪呢?"); NSLog(@"BBBBBBBBBBBBBBBBBBBB"); } void test2() { NSLog(@"AAAAAAAAAAAAAAAAAAAA"); NSLog(@"星期一,昨天玩的好累不想上班."); NSLog(@"BBBBBBBBBBBBBBBBBBBB"); } void test3() { NSLog(@"AAAAAAAAAAAAAAAAAAAA"); NSLog(@"星期二,昨天的任務還沒完成"); NSLog(@"BBBBBBBBBBBBBBBBBBBB"); }
經過block優化,分析中間部分代碼,不須要參數,返回值,定義無參無反的block:
typedef void(^myBlock)()
將四個函數抽取爲一個
void test(myBlock myLife) { NSLog(@"AAAAAAAAAAAAAAAAAAAA");
if(myLife){//判斷block是否爲nil,不然可能報錯,會報什麼錯呢?,爲何是nil呢,nil不是用於OC對象爲空的狀況麼?block是基本數據類型?仍是OC類型?
myLife();
} NSLog(@"BBBBBBBBBBBBBBBBBBBB"); }
main函數中就能夠這樣寫:
test(^(){
NSLog(@"星期天,今天去哪兒浪呢?");
});
test(^(){
NSLog(@"星期一,昨天玩的好累不想上班.");
});
test(^(){
NSLog(@"星期二,昨天的任務還沒完成");
});
>6.做爲函數返回值
typedef void(^myBlock)(); myBlock test4() { return ^(){ }; }
>7.利用block在不一樣對象間進行傳值
假設A須要傳值給B,那麼須要在A中定義一個block屬性,在須要的時候傳遞值,先判斷是否爲nil,不爲nil則調用block.
須要在B中聲明一個屬性(有東西接收就能夠,不必定就要定義屬性),用以接收傳遞過來的值,B必須拿到A,好比A成爲B的屬性,那麼就能夠獲取A的block屬性,並定義,判斷的時候,block就已經定義了,就能夠實現傳值了.
例子:
控制器的View上有一個綠色的View,當點擊屏幕的時候,傳遞一個NSInteger數據給控制器.
分析:
綠色的View爲數據的傳遞者,控制器爲接收者,所以,須要給綠色的View聲明一個block類型的屬性,所以自定義一個GreenView的類用於描述綠色的View,並在其中聲明block屬性
typedef void(^GreenViewBlock)(NSInteger index); @property (nonatomic,copy) GreenViewBlock myBlock;
當點擊屏幕的時候傳遞數據,於是重寫touchesBegin方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { if (_myBlock) {//若是實現了,就調用 _myBlock(11); } }
控制器爲接收者,於是給控制器聲明一個屬性用於接收數據,又由於,須要在控制器中初始化block,這樣點擊屏幕是block不爲nil,實現傳值,於是須要得到綠色的View的屬性block,於是,將綠色的View拖成控制器的屬性
@property (nonatomic,assign) NSInteger index;
@property (weak, nonatomic) IBOutlet GreenView *greenView;
//初始化block
_greenView.myBlock = ^(NSInteger index){ self.index = index; };
//上面的賦值操做便是調用index的setter方法,於是此時便可得到傳遞過來的數據
- (void)setIndex:(NSInteger)index { _index = index; NSLog(@"%ld",index); }
>8.注意:
block內部默認不能修改外部的局部變量
用__block修飾局部變量,在block中就能夠訪問了.