Block介紹(二)記憶體管理與其他特性

2021-06-18 13:02:16 字數 3006 閱讀 4319

我們在前一章介紹了block的用法,而正確使用block必須要求正確理解block的記憶體管理問題。

這一章,我們只陳述結果而不追尋原因,我們將在下一章深入其原因。

我們針對不同情況來討論block的存放位置:

以下情況中的block位於堆中:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

voidfoo()

;//blk在棧裡

blkinheap = block_copy(blk);//blkinheap在堆裡

}

- (void)foobar

;

void(^oblkinheap)(void) = [oblkcopy];//oblkinheap在堆中

}

以下情況中的block位於全域性區: 

1

2

3

4

5

6

7

8

9

10

staticint(^maxintblock)(int,int) = ^(inta,intb);

- (void)foobar

voidfoo()

需要注意的是,這裡複製過後的block依舊位於全域性區,實際上,複製操作是直接返回了原block物件。 

全域性區的變數儲存位置與block無關:

1

2

3

4

5

6

7

8

staticintgvar =0;

//__block static int gmvar = 1;

voidfoo()

注意,static變數是不允許新增__block標記的

此時,你可能會問,當函式foo返回後,棧上的j已經**,那麼blkinheap怎麼能繼續使用它?這是因為沒有__block標記的變數,會被當做實參傳入block的底層實現函式中,當block中的**被執行時,j已經不是原來的j了,所謂物是人非就是這樣吧~

另外,如果使用到變數j的所有block都沒有被複製至heap,那麼這個變數j也不會被複製至heap。

因此,即使將j++這一句放到blk()這句之前,這段**執行後,控制台列印結果也是:1024, 1。而不是1024, 2

對block呼叫複製,有以下幾種情況:

1.對全域性區的block呼叫copy,會返回原指標,並且這期間不處理任何東西(至少目前的內部實現是這樣);

2.對棧上的block呼叫copy,每次會返回新複製到堆上的block的指標,同時,所有__block變數都會被複製至堆乙份(多次拷貝,只會生成乙份)。

3.對已經位於heap上的block,再次呼叫copy,只會增加block的引用計數。

為什麼我們不討論retian的行為?原因是並沒有block_retain()這樣的函式,而且objc裡面的retain訊息傳送給block物件後,其內部實現是什麼都不做。 

objc類例項方法中的block如果被複製至heap,那麼當前例項會被增加引用計數,當這個block被釋放時,此例項會被減少引用計數。

但如果這個block沒有使用當前例項的任何成員,那麼當前例項不會被增加引用計數。這也是很自然的道理,我既然沒有用到這個instance的任何東西,那麼我幹嘛要retian它?

我們要注意的一點是,我看到網上有很多人說block引起了例項與block之間的迴圈引用(retain-cycle),並且給出解決方案:不直接使用self而先將self賦值給乙個臨時變數,然後再使用這個臨時變數。

但是,大家注意,我們一定要為這個臨時變數增加__block標記(多謝第三篇文章回帖網友的提醒)。

這一章我們以結果導向的方式來說明了各種情況下,block的記憶體問題,下一章,我將剖析執行時庫的原始碼,從根源闡述block的行為。也就是過程導向的方式了。

Block介紹(二)記憶體管理與其他特性

一 block放在 我們針對不同情況來討論block的存放位置 1.棧和堆 以下情況中的block位於堆中 12 3456 78910 1112 1314 1516 17voidfoo blk在棧裡 blkinheap block copy blk blkinheap在堆裡 void foobar ...

Block介紹(二)記憶體管理與其他特徵

我們在前一章介紹了block的用法,而正確使用block必須要求正確理解block的記憶體管理問題。這一章,我們只陳述結果而不追尋原因,我們將在下一章深入其原因。我們針對不同情況來討論block的存放位置 以下情況中的block位於堆中 1 2 3 4 5 6 7 8 9 10 11 12 13 1...

iOS中Block介紹(二)記憶體管理與其他特性

我們針對不同情況來討論block的存放位置 1.棧和堆 以下情況中的block位於堆中 void foo blk在棧裡 blkinheap block copy blk blkinheap在堆裡 void foobar void oblkinheap void oblk copy oblkinhea...