Block
block其實(shí)就是一個(gè)代碼塊良漱,把你想要執(zhí)行的代碼封裝在這個(gè)代碼塊里椿疗,等到需要的時(shí)候再去調(diào)用该肴。那block是OC對象嗎葛假?答案是肯定的
1障陶、為什么block中要使用__weak來修飾self?
循環(huán)引用聊训,block在iOS中被視為對象抱究,因此它的生命周期會(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
原因就是對局部變量num的截獲是值截獲苦银。就是創(chuàng)建block的時(shí)候啸胧,已經(jīng)把a(bǔ)ge的值存儲(chǔ)在里面了
同樣,在block里如果修改變量num幔虏,也是無效的纺念,甚至編譯器會(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)體對象
Q:block對全局變量的捕獲方式是眷唉?
block不需要對全局變量捕獲,都是直接采用取值的
Q:為什么局部變量需要捕獲囤官?
考慮作用域的問題冬阳,需要跨函數(shù)訪問,就需要捕獲
3党饮、根據(jù)Block創(chuàng)建的位置不同肝陪,Block有三種類型,創(chuàng)建的Block對象分別會(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對棧block進(jìn)行copy操作狼讨,就是堆block,對全局block進(jìn)行copy操作還是全局block
即如果對棧Block進(jìn)行copy柒竞,將會(huì)copy到堆區(qū)政供,對堆Block進(jìn)行copy,將會(huì)增加引用計(jì)數(shù),對全局Block進(jìn)行copy布隔,因?yàn)槭且呀?jīng)初始化的离陶,所以什么也不做。
4衅檀、block為什么用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)對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)建的對象隨時(shí)可能被銷毀具垫,一旦被銷毀后續(xù)調(diào)用這個(gè)空對象就會(huì)導(dǎo)致程序崩潰,而對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擒滑、無參無返回
void (^ MyBlockOne)(void) = ^(void){
? ? NSLog(@"無參數(shù)腐晾,無返回值");?
};?
MyBlockOne();//block的調(diào)用
5.2、有參無返回
void(^MyblockTwo)(int a) = ^(int a){
? ? NSLog(@"@ = %d我就是block丐一,有參數(shù)藻糖,無返回值",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、無參有返回
int(^MyblockFour)(void) = ^{
? ? NSLog(@"無參數(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對象的本身,那必須添加__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);