Block探究
block的本質(zhì)問題
- block其實(shí)是一個(gè)oc對(duì)象,因?yàn)槠浣Y(jié)構(gòu)體第一個(gè)成員為class類型的isa指針.
struct main_block_impl_0 {
struct block_impl {
Void *isa;
Void *FuncPtr; // 指向block內(nèi)部保存的函數(shù)調(diào)用地址
}
ivars// block內(nèi)部包含的屬性
// int 為直接捕獲值, 對(duì)象為指針引用
}
block的類型
- Global_block 全局block, 內(nèi)部沒有auto 變量,
- stack_block 棧block, 內(nèi)部含有auto變量
- malloc_block 堆block, 內(nèi)部有auto變量,并且被copy到堆上的block
auto變量,C語言的局部變量使用auto修飾的.
block 對(duì)變量的捕獲方式:
- 如果是auto局部變量, 那么就會(huì)捕獲, 如果是基本數(shù)據(jù),就值的捕獲,如果是對(duì)象,就指針捕獲.
- 如果是static局部變量, 也會(huì)捕獲,捕獲方式是指針傳遞,static只是改變生命周期,不會(huì)改變?cè)L問范圍.
- 其他全局變量都是不捕獲,為直接訪問,因?yàn)槿肿兞克械胤蕉寄茉L問,就不需要捕獲,全局變量包括全局靜態(tài)變量.
block引用內(nèi)存管理問題
- 在arc下, 用強(qiáng)指針指向block, 系統(tǒng)會(huì)自動(dòng)對(duì)block進(jìn)行一次copy操作,如果是stack的block, block會(huì)升級(jí)為malloc block,malloc block copy只是引用計(jì)數(shù)加1, global block copy操作沒有作用,然后block內(nèi)部屬性,會(huì)因?yàn)樾揎椃?hào)而被block強(qiáng)引用或者弱引用,調(diào)用block的copy方法,對(duì)內(nèi)部屬性進(jìn)行強(qiáng)弱引用,釋放時(shí)候調(diào)用dispose函數(shù),減少引用計(jì)數(shù).
- 在mrc下,強(qiáng)指針不會(huì)對(duì)block對(duì)象進(jìn)行copy操作,所以如果block是stack類型block,那么block對(duì)內(nèi)部對(duì)象都不會(huì)產(chǎn)生強(qiáng)引用.
關(guān)于__block修飾屬性問題
- __block本質(zhì)上會(huì)將修飾屬性包裝成一個(gè)對(duì)象,內(nèi)部有__forwarding指針,指向自己,在copy的時(shí)候,棧上的_forwarding指向堆上,并且內(nèi)部有保存修飾的屬性,所以當(dāng)你在函數(shù)內(nèi)部訪問局部變量的時(shí)候,會(huì)通過forwarding指針找到堆上的變量,訪問block修改過后的值,而不是原本棧上的值.
為什么不能修改局部非靜態(tài)變量? 因?yàn)?個(gè)空間不同,堆上的對(duì)象不能修改棧上的指針,因?yàn)闂I系膶?duì)象生命周期不可控,同時(shí)block的作用域與局部變量的作用域不同,所以不能直接修改.
至于為什么要copy到malloc上,因?yàn)閷?duì)于程序員而言,stack的生命周期不可控,而我們希望block一般在之后調(diào)用,所以要copy到malloc上控制其生命周期.
- 當(dāng)block在棧上時(shí), __block并不會(huì)對(duì)所修飾的屬性產(chǎn)生強(qiáng)引用,但是當(dāng)被copy到堆上時(shí),會(huì)調(diào)用block_object_assgin,根據(jù)修飾的屬性是strong還是weak產(chǎn)生對(duì)應(yīng)的引用,移除的時(shí)候調(diào)用block_object_dispos函數(shù)釋放對(duì)象,
- 在mrc下__block能消除循環(huán)引用,因?yàn)開_block修飾的屬性并不會(huì)retain使引用計(jì)數(shù)加1,所以
self -> block -> __block
所以不會(huì)產(chǎn)生循環(huán)引用; - __block在arc下產(chǎn)生的循環(huán)引用最少為3個(gè)對(duì)象,因?yàn)開_block會(huì)變?yōu)閷?duì)象
關(guān)于__weak, __unsafe_unretained區(qū)別
- 都是為了解決循環(huán)引用問題,但是weak是安全的,因?yàn)橐脤?duì)象被銷毀后,會(huì)將指針變?yōu)閚il,而__unsafe_unretained不會(huì),所以會(huì)產(chǎn)生野指針.