程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> block存儲區域——如何驗證block在棧上,還是堆上

block存儲區域——如何驗證block在棧上,還是堆上

編輯:C++入門知識

block存儲區域——如何驗證block在棧上,還是堆上


block存儲區域

這就需要引入三個名詞: ● _NSConcretStackBlock ● _NSConcretGlobalBlock
● _NSConcretMallocBlock
正如它們名字說的那樣,說明了block的三種存儲方式:棧、全局、堆。 【要點1】定義在函數外面的block是global的;另外如果函數內部的block,但是沒有捕獲任何自動變量,那麼它也是全局的。比如下面這樣的代碼:
typedef int (^blk_t)(int);
for(...){
    blk_t blk = ^(int count) {return count;};
}
雖然,這個block在循環內,但是blk的地址總是不變的。說明這個block在全局段。 【要點2】一種情況在非ARC下是無法編譯的: typedef int(^blk_t)(int); blk_t func(int rate){ return ^(int count){return rate*count;} } 這是因為:block捕獲了棧上的rate自動變量,此時rate已經變成了一個結構體,而block中擁有這個結構體的指針。即如果返回block的話就是返回局部變量的指針。而這一點恰是編譯器已經斷定了。在ARC下沒有這個問題,是因為ARC使用了autorelease了。 【要點3】有時候我們需要調用block 的copy函數,將block拷貝到堆上。看下面的代碼:
-(id) getBlockArray{
    int val =10;
    return [[NSArray alloc]initWithObjects:
        ^{NSLog(@"blk0:%d",val);},
        ^{NSLog(@"blk1:%d",val);},nil];
}

id obj = getBlockArray();
typedef void (^blk_t)(void);
blk_t blk = (blk_t){obj objectAtIndex:0};
blk();
這段代碼在最後一行blk()會異常,因為數組中的block是棧上的。因為val是棧上的。解決辦法就是調用copy方法。 【要點4】不管block配置在何處,用copy方法復制都不會引起任何問題。在ARC環境下,如果不確定是否要copy block盡管copy即可。ARC會打掃戰場。 注意:在棧上調用copy那麼復制到堆上,在全局block調用copy什麼也不做,在堆上調用block 引用計數增加

本人用Xcode 5.1.1 iOS sdk 7.1 編譯發現:並非《Objective-C》高級編程這本書中描述的那樣,看下面代碼 int val肯定是在棧上的,我保存了val的地址,看看block調用前後是否變化。輸出一致說明是棧上,不一致說明是堆上。
typedef int (^blkt1)(void) ;
-(void) stackOrHeap{
    __block int val =10;
    int *valPtr = &val;//使用int的指針,來檢測block到底在棧上,還是堆上
    blkt1 s= ^{
        NSLog(@"val_block = %d",++val);
        return val;};
    s();
    NSLog(@"valPointer = %d",*valPtr);
}
在ARC下>>>>>>>>>>>該block被會直接生成到堆上了。看log: val_block = 11 valPointer = 10 在非ARC下>>>>>>>>>該block還是在棧上的。 看log:val_block = 11 valPointer = 11

調用copy之後的結果呢:

-(void) stackOrHeap{
    __block int val =10;
    int *valPtr = &val;//使用int的指針,來檢測block到底在棧上,還是堆上
    blkt1 s= ^{
        NSLog(@"val_block = %d",++val);
        return val;};
    blkt1 h = [s copy];
    h();
    NSLog(@"valPointer = %d",*valPtr);
}

----------------在ARC下>>>>>>>>>>>無效果。 val_block = 11 valPointer = 10

----------------在非ARC下>>>>>>>>>確實復制到堆上了。 val_block = 11 valPointer = 10
用這個表格來表示 /*當block捕獲了自動變量時候 ------------------------------------------------------------------ | where block stay | ARC | 非ARC | -------------------------------------------------------------------
| copy | heap | heap | ------------------------------------------------------------------ | no copy | heap | stack | ------------------------------------------------------------------
*/ 詳細內容見 點擊打開鏈接

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved