block

block的原理是怎樣的?本質(zhì)是什么?

block本質(zhì)上是一個(gè)OC對(duì)象 他內(nèi)部也有isa指針
block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境的OC對(duì)象

__block的作用是什么?有什么使用注意點(diǎn)?

解決block內(nèi)部無(wú)法修改auto變量值的問(wèn)題
會(huì)把__block變量包裝成一個(gè)對(duì)象

block的屬性修飾詞為什么是copy?使用block有哪些使用注意?

block一旦沒(méi)有進(jìn)行copy操作 就不會(huì)在堆上
注意循環(huán)引用的問(wèn)題

block在修改NSMutableArray,需不需要添加__block?

不需要
__block是修改auto變量的值
NSMutableArray addobject是使用了這個(gè)指針

block本質(zhì)

block本質(zhì)上是一個(gè)OC對(duì)象 他內(nèi)部也有isa指針
block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境的OC對(duì)象
block本質(zhì).png

block的變量捕獲(capture)

auto 自動(dòng)變量 離開(kāi)作用域就銷(xiāo)毀
只要是局部變量 block要訪(fǎng)問(wèn)局部變量 就要捕獲

#block的變量捕獲.png

自動(dòng)變量只能傳值的原因是隨時(shí)可能會(huì)銷(xiāo)毀 那塊地址就沒(méi)了 如果再傳地址進(jìn)去 就會(huì)訪(fǎng)問(wèn)到壞內(nèi)存 static變量是因?yàn)槟菈K內(nèi)存存在 可以通過(guò)地址來(lái)進(jìn)行訪(fǎng)問(wèn)
局部變量需要捕獲的原因是因?yàn)橐绾瘮?shù)訪(fǎng)問(wèn) 全局變量是任何函數(shù)都可以直接使用,所以不需要進(jìn)行捕獲

block的類(lèi)型

block有3種類(lèi)型,可以通過(guò)調(diào)用class方法或者isa指針查看具體類(lèi)型,最終都是繼承自NSBlock類(lèi)型

__NSGlobalBlock__ ( _NSConcreteGlobalBlock )
__NSStackBlock__  ( _NSConcreteStackBlock )
__NSMallocBlock__ ( _NSConcreteMallocBlock )

一切以運(yùn)行時(shí)的結(jié)果為準(zhǔn) 使用Clang轉(zhuǎn)成的C++代碼不一定完全一致 只能作為參考

block的三種類(lèi)型分別存放的位置.png

根據(jù)環(huán)境判斷block類(lèi)型.png

在棧block里面 函數(shù)調(diào)用完畢 里面的數(shù)據(jù)可能是垃圾數(shù)據(jù)

block類(lèi)調(diào)用copy后的結(jié)果.png

在ARC環(huán)境下,編譯器會(huì)根據(jù)情況自動(dòng)將棧上的block復(fù)制到堆上

1.block作為函數(shù)返回值的時(shí)候
2.將block賦值給強(qiáng)指針(__strong)的時(shí)候
3.block作為Cocoa API中方法名含有usingBlock的方法參數(shù)時(shí)
4.block作為GCD API的方法參數(shù)時(shí)

??臻g的block是無(wú)法對(duì)外面的變量進(jìn)行持有的 也就是強(qiáng)引用的 堆空間的block會(huì)對(duì)外面的變量進(jìn)行強(qiáng)引用的 保住他的生命(當(dāng)block銷(xiāo)毀的時(shí)候 也會(huì)對(duì)變量進(jìn)行release)

如果代碼里面使用了__weak 在使用clang轉(zhuǎn)換OC為C++代碼時(shí),可能會(huì)遇到cannot create __weak reference in file using manual reference 那么需要指定運(yùn)行時(shí)版本 需要arc

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m

對(duì)象類(lèi)型的auto變量

當(dāng)block內(nèi)部訪(fǎng)問(wèn)了對(duì)象類(lèi)型的auto變量時(shí)
  1.如果block是在棧上 都不會(huì)對(duì)auto變量產(chǎn)生強(qiáng)引用
  2.如果block被拷貝到堆上
    @.會(huì)調(diào)用block內(nèi)部的copy函數(shù)
    @.copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)
    @._Block_object_assign 函數(shù)會(huì)根據(jù)auto變量的修飾符(__strong、__weak、__unsafe_unretained)做出
     相應(yīng)的操作,形成強(qiáng)引用(retain)或者弱引用
  3.如果block從堆上移除
    @.會(huì)調(diào)用block內(nèi)部的dispose函數(shù)
    @.dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)
    @._Block_object_dispose函數(shù)會(huì)自動(dòng)釋放引用的auto變量 類(lèi)似于release
調(diào)用時(shí)機(jī).png

解決block內(nèi)部無(wú)法修改auto變量值的問(wèn)題

1.使用static修飾 會(huì)把變量地址捕獲到block里面
2.使用全局變量來(lái) 不會(huì)捕獲到block里面 直接就可以修改
3.使用__block修飾

不使用static變量和全局變量的原因是 不想創(chuàng)建一個(gè)變量永遠(yuǎn)占據(jù)這塊內(nèi)存
__block不能修飾全局變量、靜態(tài)變量(static)
編譯器會(huì)將__block變量包裝成一個(gè)對(duì)象

block的內(nèi)部結(jié)構(gòu).png

__block修飾的變量會(huì)變成一個(gè)對(duì)象 就是一個(gè)結(jié)構(gòu)體.png

__block變量的結(jié)構(gòu)體的內(nèi)部結(jié)構(gòu).png

__block修飾auto變量的內(nèi)存管理

__block修飾變量的時(shí)候
1.當(dāng)block在棧上時(shí) 并不會(huì)對(duì)__block變量產(chǎn)生強(qiáng)引用
2.當(dāng)block被copy到堆時(shí)
  a.會(huì)調(diào)用block內(nèi)部的copy函數(shù)
  b.copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)
  c. _Block_object_assign函數(shù)會(huì)對(duì)__block變量形成強(qiáng)引用(retain)
圖1.png

圖2.png
block銷(xiāo)毀的時(shí)候
當(dāng)block從堆中移除時(shí)
- 會(huì)調(diào)用block內(nèi)部的dispose函數(shù)
- dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)
- _Block_object_dispose函數(shù)會(huì)自動(dòng)釋放引用的__block變量(release)
image1.png

image2.png

對(duì)象類(lèi)型的auto變量、__block修飾的auto變量的內(nèi)存管理總結(jié)

1.當(dāng)block在棧上的時(shí)候 都不會(huì)產(chǎn)生強(qiáng)引用
2.當(dāng)block拷貝到堆上時(shí)  通過(guò)copy函數(shù)處理他們
  a. __block變量(假設(shè)變量名叫做a)
   _Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);  
  b.對(duì)象類(lèi)型的auto變量(假設(shè)變量名叫做p)
  _Block_object_assign((void*)&dst->p, (void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);
3.當(dāng)block從堆上移除時(shí),都會(huì)通過(guò)dispose函數(shù)來(lái)釋放它們
  a.__block變量(假設(shè)變量名叫做a)
   _Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
  b.對(duì)象類(lèi)型的auto變量(假設(shè)變量名叫做p)
   _Block_object_dispose((void*)src->p, 3/*BLOCK_FIELD_IS_OBJECT*/);

__block的__forwarding指針

__forwarding指針.png

保證不管訪(fǎng)問(wèn)的是棧中的block還是堆中的block 只要通過(guò)__forwarding指針都可以訪(fǎng)問(wèn)到堆中的block

__block修飾對(duì)象類(lèi)型的內(nèi)存管理

當(dāng)block拷貝到堆上 會(huì)把__block修飾的對(duì)象這個(gè)整體的結(jié)構(gòu)體拷貝到堆上 同時(shí),會(huì)調(diào)用這個(gè)結(jié)構(gòu)體內(nèi)部的copy函數(shù)

1.當(dāng)__block變量在棧上時(shí),不會(huì)對(duì)指向的對(duì)象產(chǎn)生強(qiáng)引用
2.當(dāng)__block變量被copy到堆時(shí)
  a.會(huì)調(diào)用__block變量?jī)?nèi)部的copy函數(shù)
  b.copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)
  c._Block_object_assign函數(shù)會(huì)根據(jù)所指向?qū)ο蟮男揎椃╛_strong、__weak、__unsafe_unretained)做出相應(yīng)
  的操作,形成強(qiáng)引用(retain)或者弱引用(注意:這里僅限于ARC時(shí)會(huì)retain,MRC時(shí)不會(huì)retain)
3.如果__block變量從堆上移除
  a.會(huì)調(diào)用__block變量?jī)?nèi)部的dispose函數(shù)
  b.dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)
  c._Block_object_dispose函數(shù)會(huì)自動(dòng)釋放指向的對(duì)象(release)

這里僅限于ARC時(shí)會(huì)retain,MRC時(shí)不會(huì)retain

解決循環(huán)引用問(wèn)題 -ARC

用__weak、__unsafe_unretained解決

weak 不會(huì)產(chǎn)生強(qiáng)引用 指向的對(duì)象銷(xiāo)毀時(shí) 會(huì)自動(dòng)讓指針置為nil
__unsafe_unretained 不會(huì)產(chǎn)生強(qiáng)引用 不安全 指向的對(duì)象銷(xiāo)毀時(shí) 指針存儲(chǔ)的地址值不變

可以使用__block來(lái)解決循環(huán)引用問(wèn)題 但是 必須要執(zhí)行block 和把對(duì)象置為nil 如果沒(méi)有執(zhí)行block 那么就會(huì)存在循環(huán)引用

__block id weakSelf = self;
self.block = ^{
  printf( "%p", weakSelf);
  weakSelf = nil ;
};
self.block() ;

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

在MRC下不支持__weak

用__block、__unsafe_unretained解決

由于在MRC下 使用__block修飾變量 不會(huì)對(duì)變量產(chǎn)生強(qiáng)引用 這樣就可以使用__block來(lái)解決循環(huán)引用問(wèn)題

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

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

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