Block本質(zhì)
block本質(zhì)上也是一個OC對象,它內(nèi)部也有個isa指針
block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境的OC對象
block的底層結(jié)構(gòu)如下圖所示

Block變量捕獲
| 變量類型 | 捕獲到block 內(nèi)部 | 訪問方式 |
|---|---|---|
| 局部auto變量 | √ | 值傳遞 |
| 局部static變量 | √ | 指針傳遞 |
| 全局變量 | × | 直接訪問 |
Auto變量的捕獲

block類型
block有3種類型,可以通過調(diào)用class方法或者isa指針查看具體類型,最終都是繼承自NSBlock類型
__NSGlobalBlock__ ( _NSConcreteGlobalBlock )
__NSStackBlock__ ( _NSConcreteStackBlock )
__NSMallocBlock__ ( _NSConcreteMallocBlock )
| **block ** 類型 | 環(huán)境 |
|---|---|
| __NSGlobalBlock__ | 沒有訪問auto變量 |
| _NSStackBlock_ | 訪問了auto變量 |
| _NSMallocBlock_ | _NSStackBlock_調(diào)用了copy |
每一種類型的block調(diào)用copy后的結(jié)果如下所示

Block 的copy
在ARC環(huán)境下,編譯器會根據(jù)情況自動將棧上的block復(fù)制到堆上,比如以下情況
- block作為函數(shù)返回值時
- 將block賦值給__strong指針時
- block作為Cocoa API中方法名含有usingBlock的方法參數(shù)時
- block作為GCD API的方法參數(shù)時
MRC下block屬性的建議寫法
@property (copy, nonatomic) void (^block)(void);
ARC下block屬性的建議寫法
@property (strong, nonatomic) void (^block)(void);
@property (copy, nonatomic) void (^block)(void);
訪問對象類型的auto變量
當block內(nèi)部訪問了對象類型的auto變量時
如果block是在棧上,將不會對auto變量產(chǎn)生強引用
如果block被拷貝到堆上
- 會調(diào)用block內(nèi)部的copy函數(shù)
- copy函數(shù)內(nèi)部會調(diào)用Block_object_assign函數(shù)
- Block_object_assign函數(shù)會根據(jù)auto變量的修飾符(__strong、__weak、__unsafe_unretained)做出相應(yīng)的操作,形成強引用(retain)或者弱引用
如果block從堆上移除
- 會調(diào)用block內(nèi)部的dispose函數(shù)
- dispose函數(shù)內(nèi)部會調(diào)用Block_object_dispose函數(shù)
- Block_object_dispose函數(shù)會自動釋放引用的auto變量(release)

__weak問題解決
在使用clang轉(zhuǎn)換OC為C++代碼時,可能會遇到以下問題
cannot create __weak reference in file using manual reference
解決方案:支持ARC、指定運行時系統(tǒng)版本,比如
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m
__block修飾符
__block可以用于解決block內(nèi)部無法修改auto變量值的問題
__block不能修飾全局變量、靜態(tài)變量(static)
編譯器會將__block變量包裝成一個對象

__Block的內(nèi)存管理
當block在棧上時,并不會對__block變量產(chǎn)生強引用
當block被copy到堆時
- 會調(diào)用block內(nèi)部的copy函數(shù)
- copy函數(shù)內(nèi)部會調(diào)用Block_object_assign函數(shù)
- Block_object_assign函數(shù)會對__block變量形成強引用(retain)

當block從堆中移除時
- 會調(diào)用block內(nèi)部的dispose函數(shù)
- dispose函數(shù)內(nèi)部會調(diào)用Block_object_dispose函數(shù)
- Block_object_dispose函數(shù)會自動釋放引用的__block變量(release)

block的forwarding指針

對象類型的auto變量,__block變量
當block在棧上時,對它們都不會產(chǎn)生強引用
當block拷貝到堆上時,都會通過copy函數(shù)來處理它們
__block變量(假設(shè)變量名叫做a)
_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
對象類型的auto變量(假設(shè)變量名叫做p)
_Block_object_assign((void*)&dst->p, (void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
當block從堆上移除時,都會通過dispose函數(shù)來釋放它們
__block變量(假設(shè)變量名叫做a)
_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
對象類型的auto變量(假設(shè)變量名叫做p)
_Block_object_dispose((void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
被__block修飾的對象類型
當__block變量在棧上時,不會對指向的對象產(chǎn)生強引用
當__block變量被copy到堆時
- 會調(diào)用_block變量內(nèi)部的copy函數(shù)
- _copy函數(shù)內(nèi)部會調(diào)用_Block_object_assign函數(shù)
- _Block_object_assign函數(shù)會根據(jù)所指向?qū)ο蟮男揎椃?__strong、__weak、__unsafe_unretained)做出相應(yīng)的操作,形成強引用(retain)或者弱引用(注意:這里僅限于ARC時會retain,MRC時不會retain)
如果__block變量從堆上移除
- 會調(diào)用_block變量內(nèi)部的dispose函數(shù)
- _dispose函數(shù)內(nèi)部會調(diào)用_Block_object_dispose函數(shù)
- _Block_object_dispose函數(shù)會自動釋放指向的對象(release)
解決循環(huán)引用問題 - ARC

解決循環(huán)引用問題 - MRC

__weak, __strong作用
__weak typeof(self) wself = self;
__strong typeof(self) sself = wself;
__weak弱引用指針,避免循環(huán)引用
__strong避免在使用過程中,對象被銷毀