Block整理

Block

block其實(shí)就是一個(gè)代碼塊,把你想要執(zhí)行的代碼封裝在這個(gè)代碼塊里,等到需要的時(shí)候再去調(diào)用。那block是OC對(duì)象嗎?答案是肯定的

1、為什么block中要使用__weak來(lái)修飾self?

循環(huán)引用,block在iOS中被視為對(duì)象,因此它的生命周期會(huì)等到它的持有者生命周期結(jié)束才會(huì)結(jié)束;另一方面,由于block捕獲變量的機(jī)制,self也會(huì)被block持有;導(dǎo)致循環(huán)引用。

2、Block的變量截獲

2.1局部變量截獲 是值截獲

//? ? __block NSInteger num = 3;

? ? NSInteger num = 3;

? ? NSInteger(^block)(NSInteger) = ^NSInteger(NSInteger n){

? ? ? ? returnn*num;

? ? };

? ? num = 1;

NSLog(@"%ld",(long)block(2));

//輸出6,加上__block,則輸出2

原因就是對(duì)局部變量num的截獲是值截獲。就是創(chuàng)建block的時(shí)候,已經(jīng)把a(bǔ)ge的值存儲(chǔ)在里面了

同樣,在block里如果修改變量num,也是無(wú)效的,甚至編譯器會(huì)報(bào)錯(cuò)。

2.2局部靜態(tài)變量截獲 是指針截獲,

static? NSInteger num = 3;

NSInteger(^block)(NSInteger) = ^NSInteger(NSInteger n){

? ? ? ? return?n*num;

? ? };

? ? num = 1;

NSLog(@"%ld",(long)block(2));

輸出為2,意味著num = 1這里的修改num值是有效的,即是指針截獲。

同樣,在block里去修改變量m,也是有效的。

2.3可以看到局部變量被編譯成值形式,而靜態(tài)變量被編成指針形式,全局變量并未截獲。而__block修飾的變量也是以指針形式截獲的,并且生成了一個(gè)新的結(jié)構(gòu)體對(duì)象

Qblock對(duì)全局變量的捕獲方式是?

block不需要對(duì)全局變量捕獲,都是直接采用取值的

Q:為什么局部變量需要捕獲?

考慮作用域的問題,需要跨函數(shù)訪問,就需要捕獲

3、根據(jù)Block創(chuàng)建的位置不同,Block有三種類型,創(chuàng)建的Block對(duì)象分別會(huì)存儲(chǔ)到棧(NSStackBlock)、堆(NSMallocBlock)、全局?jǐn)?shù)據(jù)區(qū)域(NSGlobalBlock)

3.1 不使用外部變量的block是全局block,存儲(chǔ)在全局?jǐn)?shù)據(jù)區(qū)域

3.2使用了外部變量,但未進(jìn)行copy操作的block是棧block

3.3對(duì)棧block進(jìn)行copy操作,就是堆block,對(duì)全局block進(jìn)行copy操作還是全局block

即如果對(duì)棧Block進(jìn)行copy,將會(huì)copy到堆區(qū),對(duì)堆Block進(jìn)行copy,將會(huì)增加引用計(jì)數(shù),對(duì)全局Block進(jìn)行copy,因?yàn)槭且呀?jīng)初始化的,所以什么也不做。

4block為什么用copy修飾

因?yàn)樵?b>MRC下,block在創(chuàng)建的時(shí)候,它的內(nèi)存是分配在棧(stack)上的,而不是在堆(heap)上,可能被隨時(shí)回收。他本身的作于域是屬于創(chuàng)建時(shí)候的作用域,一旦在創(chuàng)建時(shí)候的作用域外面調(diào)用block將導(dǎo)致程序崩潰。通過copy可以把block拷貝(copy)到堆,保證block的聲明域外使用。在ARC下寫不寫都行,編譯器會(huì)自動(dòng)對(duì)block進(jìn)行copy操作。

Block創(chuàng)建的時(shí)候它的內(nèi)存是分配在棧中的,它本身的作用域就是創(chuàng)建的時(shí)候的作用域,如果在此作用域外部調(diào)用block就會(huì)導(dǎo)致程序崩潰。因?yàn)闂^(qū)的特點(diǎn)就是創(chuàng)建的對(duì)象隨時(shí)可能被銷毀,一旦被銷毀后續(xù)調(diào)用這個(gè)空對(duì)象就會(huì)導(dǎo)致程序崩潰,而對(duì)block進(jìn)行copy,block的內(nèi)存就會(huì)分配到堆區(qū)。

使用retain也可以(有警告),但是block的retain行為默認(rèn)是用copy的行為實(shí)現(xiàn)的。

所以為了能夠在block的聲明域外使用,所以要把block拷貝(copy)到堆,所以說為了block屬性聲明和實(shí)際的操作一致,最好聲明為copy。

5、定義和使用

5.1、無(wú)參無(wú)返回

void (^ MyBlockOne)(void) = ^(void){

? ? NSLog(@"無(wú)參數(shù),無(wú)返回值");?

};?

MyBlockOne();//block的調(diào)用

5.2、有參無(wú)返回

void(^MyblockTwo)(int a) = ^(int a){

? ? NSLog(@"@ = %d我就是block,有參數(shù),無(wú)返回值",a);

};?

MyblockTwo(100);

5.3、有參有返回

int(^MyBlockThree)(int,int) = ^(int a,int b){? ?

? ? NSLog(@"%d我就是block,有參數(shù),有返回值",a + b);

? ? return a + b;?

};?

MyBlockThree(12,56);

5.4、無(wú)參有返回

int(^MyblockFour)(void) = ^{

? ? NSLog(@"無(wú)參數(shù),有返回值");

? ? return45;

? };

MyblockFour();

5.5、聲明

typedef void (^Block)();

typedef int (^MyBlock)(int , int);

typedef void(^ConfirmBlock)(BOOL isOK);

typedef void(^AlertBlock)(NSInteger alertTag);

定義屬性

@property (nonatomic,copy) MyBlock myBlockOne;

使用

self.myBlockOne = ^int (int ,int){

? ? //TODO

}

block在修改NSMutableArray,需不需要添加__block?

如修改NSMutableArray的存儲(chǔ)內(nèi)容的話,是不需要添加__block修飾的。

如修改NSMutableArray對(duì)象的本身,那必須添加__block修飾。

例子:

__blockNSMutableArray *arr = [[NSMutableArray alloc]init];//不加__block,下面改變可變數(shù)組arr的時(shí)候就報(bào)錯(cuò)

? ? [arr addObject:@"1"];

? ? void(^block)(void) = ^(){

//? ? ? ? [arr addObject:@"3"];

? ? ? ? NSArray *aaaa? = @[@"2"];

? ? ? ? arr = [NSMutableArray arrayWithArray:aaaa];

? ? ? ? NSLog(@"1_%@",arr);

? ? };

? ? NSLog(@"2_%@",arr);

? ? block();

? ? NSLog(@"3_%@",arr);

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容