根據(jù)Block在內(nèi)存中的位置魄梯,Block可分為三種類型NSGlobalBlock桨螺,NSStackBlock,NSMallocBlock画恰。
NSGlobalBlock
這種Block存儲(chǔ)在程序的數(shù)據(jù)區(qū)域(跟函數(shù)存儲(chǔ)在一起)彭谁,一個(gè)沒有引用外部變量的Block即為NSGlobalBlock。對(duì)于NSGlobalBlock允扇,我們不需要使用copy缠局,即使copy,也不會(huì)copy到堆上考润!
NSStackBlock
如果Block中引用了外部變量狭园,則該Block為NSStackBlock鹉戚。
對(duì)于NSStackBlock踏堡,如果不做任何操作,隨棧自生自滅培愁。一旦block被調(diào)用井辜,則會(huì)被copy到堆上绎谦,變成NSMallocBlock。
請(qǐng)看如下代碼:
typedef void (^dBlock)();
dBlock example_getBlock() {
char d = 'aaa';
return ^{
printf("%c\n", d);
};
}
void example() {
example_getBlock()();
}
上面的代碼中粥脚,example_getBlock返回了一個(gè)NSStackBlock窃肠,正常情況下返回一個(gè)棧上的對(duì)象是會(huì)出錯(cuò)的,但是在ARC下刷允,返回的時(shí)候會(huì)將NSStackBlock拷貝到堆上冤留,而且是autorelease類型的。example_getBlock返回堆上的NSMallocBlock树灶,所以上面的代碼可以正常運(yùn)行纤怒。
再看如下代碼:
- (NSArray*) getBlockArray
{
int num = 123;
return [[NSArray alloc] initWithObjects:
^{ NSLog(@"this is block 0:%i", num); },
^{ NSLog(@"this is block 1:%i", num); },
^{ NSLog(@"this is block 2:%i", num); },
nil];
}
- (void)test
{
NSArray* obj = [self getBlockArray];
void (^blockObject)(void);
blockObject = [obj objectAtIndex:1];
blockObject();
}
這段代碼中,getBlockArray返回一個(gè)NSStackBlock數(shù)組天通,而ARC并沒有對(duì)數(shù)組中的block做任何處理泊窘,getBlockArray函數(shù)結(jié)束后,NSArray中的三個(gè)block都將被釋放。所以在test函數(shù)中州既,blockObject指向一塊已經(jīng)被釋放的棧內(nèi)存谜洽,運(yùn)行時(shí)程序會(huì)報(bào)錯(cuò)。
NSMallocBlock
默認(rèn)的block是存放在棧上的(NSStackBlock)吴叶,對(duì)于一個(gè)NSStackBlock copy一下即可copy到堆上阐虚,變成NSMallocBlock。