2016-08-02 43 views
1

我很樂意得到以下行爲的解釋:一個棘手的Objective-C塊行爲

typedef void (^MyBlock)(void); 
MyBlock g_ary[4]; 

int runBlockParam2(MyBlock callbackBlock, int num) { 
    g_ary[num] = callbackBlock; 
    return num+100; 
} 

int main(int argc, const char * argv[]) { 
    @autoreleasepool { 
     int i; 
     for (i=0; i<4; i++) { 
      __block int j; 
      int k = runBlockParam2(^{ 
       NSLog(@"in the block i=%i, j=%i", i, j); 
      }, i); 
      j=k; 
     } 
     for (i=0; i<4; i++) { 
      g_ary[i](); 
     } 
    } 
    return 0; 
} 

上面的代碼顯示以下輸出: in the block i=0, j=100 in the block i=1, j=101 in the block i=2, j=102 in the block i=3, j=103

爲什麼j改性有該塊後面的任務?

有趣的是,一提的是,如果我們去掉__block修改,我們會得到這樣的: in the block i=0, j=0 in the block i=1, j=100 in the block i=2, j=101 in the block i=3, j=102

我會很感激任何解釋,上述行爲!

回答

3

__block存儲類型會導致塊外部的變量發生任何更改,以便在塊內部看到,反之亦然。您的j = k行在塊本身在第二個for循環中運行之前運行,因此該塊在分配後會看到j

刪除__block會導致該塊捕獲j的值,與在分配之前創建塊時的值相同。您在刪除__block後調用未定義的行爲,因爲您在初始化之前捕獲了j,導致奇怪的輸出。

如果您將聲明更改爲int j = 0,那麼日誌語句將全部顯示j=0,正如您所期望的那樣。

+0

感謝您的回覆。但是'j'在下一個週期中不斷增加,那麼爲什麼它們不會全部變成103,作爲在離開'j'變量範圍之前分配給'j'的最後一個值? – ishahak

+0

你在循環內重新聲明'j',所以每個塊都有它自己所指的'j'。如果你將'__block int j;'移到循環的外面,那麼所有的塊都會打印出'j = 103' – dan

+0

謝謝@dan。我會接受你的回答。這意味着'__block'變量實際上是塊內的一個靜態變量,但只要其聲明的範圍存在,就可以在塊之外訪問! – ishahak

0

帶有__block,第j個變量將作爲指針傳遞到塊中,因此如果在賦值j=k之後調用該塊,則j現在爲100。

沒有__block只有j變量的值被傳遞到塊。在傳遞值的塊定義之後,塊本身不能更改j。所以j是0