OC之Block使用

Block本質(zhì)

block本質(zhì)上也是一個OC對象,它內(nèi)部也有個isa指針

block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境OC對象

block的底層結(jié)構(gòu)如下圖所示

image-20220601203643653

Block變量捕獲

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

Auto變量的捕獲

image-20220601204042313

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é)果如下所示

image-20220601205102084

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)
image-20220601205629873

__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變量包裝成一個對象

image-20220601205841942

__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)
image-20220601210012513

當block從堆中移除時

  • 會調(diào)用block內(nèi)部的dispose函數(shù)
  • dispose函數(shù)內(nèi)部會調(diào)用Block_object_dispose函數(shù)
  • Block_object_dispose函數(shù)會自動釋放引用的__block變量(release)
image-20220601224842718

block的forwarding指針

image-20220601224935611

對象類型的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

image-20220601230342280

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

image-20220601230407473

__weak, __strong作用

__weak typeof(self) wself = self;

__strong typeof(self) sself = wself;

__weak弱引用指針,避免循環(huán)引用

__strong避免在使用過程中,對象被銷毀

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容