三種Block在ARC下的分析

根據Block在內存中的位置,Block可分為三種類型NSGlobalBlock,NSStackBlock,NSMallocBlock。

NSGlobalBlock

這種Block存儲在程序的數據區域(跟函數存儲在一起),一個沒有引用外部變量的Block即為NSGlobalBlock。對于NSGlobalBlock,我們不需要使用copy,即使copy,也不會copy到堆上!

NSStackBlock

如果Block中引用了外部變量,則該Block為NSStackBlock。
對于NSStackBlock,如果不做任何操作,隨棧自生自滅。一旦block被調用,則會被copy到堆上,變成NSMallocBlock。
請看如下代碼:

typedef void (^dBlock)();  
  
dBlock example_getBlock() {  
    char d = 'aaa';  
    return ^{  
        printf("%c\n", d);  
    };  
}  
  
void example() {  
    example_getBlock()();  
} 

上面的代碼中,example_getBlock返回了一個NSStackBlock,正常情況下返回一個棧上的對象是會出錯的,但是在ARC下,返回的時候會將NSStackBlock拷貝到堆上,而且是autorelease類型的。example_getBlock返回堆上的NSMallocBlock,所以上面的代碼可以正常運行。

再看如下代碼:

- (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返回一個NSStackBlock數組,而ARC并沒有對數組中的block做任何處理,getBlockArray函數結束后,NSArray中的三個block都將被釋放。所以在test函數中,blockObject指向一塊已經被釋放的棧內存,運行時程序會報錯。

NSMallocBlock

默認的block是存放在棧上的(NSStackBlock),對于一個NSStackBlock copy一下即可copy到堆上,變成NSMallocBlock。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容