- 會如何定義一個block
- blcok變量的初始化
- 簡化block的定義
- 會在block內(nèi)部訪問與修改外部變量
- 會將block作為參數(shù)傳遞
- 知道block在哪
1.如何定義一個block?
1). block是1個數(shù)據(jù)類型,我們可以聲明block類型的變量. block類型的變量中專門來存儲1段代碼的.
這段代碼可以返回值可以有參數(shù).
2). block類型的變量,雖然是用來存儲1段代碼的.
但是,1個block變量中并不是任意的1段代碼都可以存儲的.
而是有限定的.
在聲明1個block類型的變量的時候 必須要指定這個block變量中可以存儲的代碼的參數(shù)和返回值描述.
一旦指定,這個block變量中只能存儲這樣的代碼段.別的格式的代碼段是無法存儲進(jìn)去的.
3). 如何去聲明block類型的變量.
a. 根據(jù)剛剛的解釋,聲明block變量的時候,要指定這個這個block變量中存儲的代碼段的返回值和參數(shù).
b. 聲明block變量的語法:
返回值類型 (^block變量名稱)(參數(shù)列表);
void (^myBlock)();
代表聲明了1個block類型的變量,變量名加做myBlock.
這個變量中只能存儲沒有返回值,也沒有參數(shù)的1段代碼.
int (^myBlock)();
代表聲明了1個block類型的變量,變量名加做myBlock.
這個變量中只能存儲返回值為int類型的,沒有參數(shù)的1段代碼.
int (^myBlock)(int num1,int num2);
代表聲明了1個block類型的變量,變量名加做myBlock.
這個變量中只能存儲返回值為int類型的,并且有兩個整型的參數(shù)的1段代碼.
c. 特別注意:
1個block變量中只能存儲和這個block變量要求相同的1短代碼.
2.block變量的初始化
1). 初始化block變量的原理: 寫1段符合block變量要求的代碼,把這段代碼存儲到這個block變量中.
2). 書寫1個block代碼段的語法格式.
^返回值類型(參數(shù)列表){
代碼;
};
3). 無參數(shù)無返回值的代碼段.
^void(){
NSLog(@"我愛你");
NSLog(@"打瞌睡的小女孩");
};
這個時候,就可以將這段代碼 通過賦值符號. 賦值給無參數(shù),無返回值的block變量.
void (^myBlock1)();
myBlock1 = ^void(){
NSLog(@"我愛你");
NSLog(@"打瞌睡的小女孩");
};
代表的意義:myBlock1變量中存儲了這段代碼;
4). 有返回值無參數(shù)的代碼段.
注意: 如果代碼段標(biāo)識了有返回值,那么在代碼段結(jié)束之前,必須要使用return返回1個數(shù)據(jù).
^int(){
int num1 = 10;
int num2 = 20;
int num3 = num1 + num2;
return num3;
};
5). 有返回值有參數(shù)的代碼段.
^int(int num1,int num2){
int num3 = num1 + num2;
return num3;
};
6). 特別強調(diào): block變量中只能存儲和這個block變量要求相同的代碼段.否則就會報語法錯誤.
3.簡化block的定義
1). 感覺到隱隱不爽的地方: 聲明1個block變量代碼太長了.
2). 將長的block變量定義變得短一些.
3). typedef: 為1個已經(jīng)存在的數(shù)據(jù)類型取1個別名.
當(dāng)1個數(shù)據(jù)類型太長的時候,我們就可以使用typedef給它定義1個短別名,這樣方便.
4). typedef也可以將1個長的block類型定義為1個短類型.
語法格式: typedef 返回值類型 (^新類型名稱)(參數(shù)列表);
typedef void (^NewType)();
代表新定義了1個類型 這個類型的名字叫做NewType.
這是1個無參數(shù)無返回值的block類型.
如果我們要定義1個無參數(shù)無返回值的block變量.直接使用NewType就可以定義了.
typedef int (^NewType)(int num1,int num2);
代表新定義了1個數(shù)據(jù)類型. 這個類型的名字叫做NewType.
這是1個返回值為int 有兩個整型參數(shù)的block類型.
如果我們要定義1個返回值為int 有兩個整型參數(shù)的block類型變量. 直接使用這個新類型就可以定義.
4. 會在block內(nèi)部訪問與修改外部變量
1). 在block代碼塊的內(nèi)部可以定義1個和外部的變量名稱相同的變量.
訪問的時候,是就近原則.
2). 在block代碼塊的內(nèi)部可以去取出外部的全局變量和局部變量的值.
但是,在block代碼塊的內(nèi)部,可以修改全局變量的值,但是不能修改外部的局部變量的值.
3). 如果就是希望在block代碼塊的內(nèi)部去修改外部的局部變量的值.
那么就給這個局部變量加個__block的修飾符.
4). block修改外部變量
// 類型 變量名 = 值;
__block int age = 100;
NSLog(@"====%p",&age); // 棧
// 使用__block修飾外部變量時, 在定義完成block之后,棧中的外部變量就是一個擺設(shè),沒有什么卵用了
void (^block)() = ^{
age = 200;
NSLog(@"block中的age = %d",age); // 200
NSLog(@"我是block = %p",&age); // 堆
};
NSLog(@"====%p",&age); // 棧
NSLog(@"age = %d",age); // 100
// 執(zhí)行block
block();
NSLog(@"====%p",&age); // 堆
NSLog(@"age = %d",age); // 200
5.將block作為參數(shù)傳遞
1). block是1個數(shù)據(jù)類型.
那么block就必須可以作為方法/函數(shù)的參數(shù).
2). 如何為函數(shù)寫1個block類型的參數(shù).
1> 只需要在函數(shù)的小括弧中寫聲明1個block類型的變量就可以.
void test(void (^block1)());
代表,這個函數(shù)有1個block參數(shù).無返回值無參數(shù)的block參數(shù).
2> 如果你覺得暈.
那么就可以使用typedef將block類型定義的短1些.
typedef void (^NewType)();
void test(NewType b1)
3). 如何調(diào)用帶block參數(shù)的函數(shù).
1> 如果調(diào)用的函數(shù)的參數(shù)是1個block類型的.
那么要求傳遞1個和形參block類型相同的block變量
可以先將符合要求的代碼存儲在1個block變量中,然后傳遞這個變量.
2> 可以直接傳遞符合要求的代碼段.
test( ^{
NSLog(@"啦啦啦啦啦,我是打瞌睡的小行家");
NSLog(@"不等天明打瞌睡");
NSLog(@"太陽出來還在打!");
});
4. 把block作為函數(shù)的參數(shù)能夠?qū)崿F(xiàn)什么效果?
之前的函數(shù)的參數(shù)能做什么事情: 可以將調(diào)用者的數(shù)據(jù)傳遞到函數(shù)的內(nèi)部去使用.
block作為參數(shù): 可以將調(diào)用者的1段代碼傳遞到函數(shù)的內(nèi)部去執(zhí)行.
5. 什么時候需要將block作為參數(shù)?
1個函數(shù)代表1個相對對獨立的功能.
函數(shù)在完成這個功能的時候,發(fā)現(xiàn)需要執(zhí)行1段代碼才可以繼續(xù)完成.
而這段代碼函數(shù)內(nèi)部不確定是什么樣的代碼
只有調(diào)用者確定.
那么這個時候,就可以將block作為函數(shù)的參數(shù).
讓調(diào)用者在調(diào)用這個函數(shù)的時候 把這段代碼傳遞進(jìn)來.
放在這里執(zhí)行.
6.知道block在哪
block有三種類型:
1> 全局block:
- 不管是ARC還是MRC,block內(nèi)部沒有訪問任何外部變量或訪問的外部變量是靜態(tài)變量時,block就是全局block
2> 堆block:
- 在MRC下,給block調(diào)用copy方法,會將棧block拷貝到堆中.
- 在MRC環(huán)境下,如果block是堆區(qū)block,需要程序猿手動release
3> 棧block:
- 在MRC環(huán)境下,block內(nèi)部訪問了外部變量時且不是靜態(tài)變量,block就是棧block
最后分享一個關(guān)于block是如何實現(xiàn)的技術(shù)博客:談Objective-C block的實現(xiàn)-唐巧