Block詳解二(底層分析)
Block專輯:
Block講解一
MRC-block與ARC-block
Block詳解一(底層分析)
今天講述Block的最後一篇,後兩篇僅僅是加深1,2篇的理解,廢話少說,開始講解!
- __block細節
- __block記憶體管理
- 迴圈引用問題
一:__block細節
大家可能會遇到下面的問題,block的內部想要修改外部的auto變數,但是編譯器會報問題!如下
如果block內部想要修改外部的auto變數,可以在int age 前面加入static修飾詞,變為靜態區域性變數(會一直存在記憶體中,反而不好),以及可以將int age程式碼移植到函式外面變為全域性變數! 除此之外還有沒有其他的做法了呢,顯然是有的,通過__block修飾,如下:
發現__block修改外面變數是可以達到目的的! 小結論
- __block可以用於解決block內部無法修飾auto變數值的問題
- __block不能修飾全域性變數、靜態變數(static)
- 編譯器會將__block變數包裝成一個物件
通過命令
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m
生成main.cpp程式碼檢視原理
上面提到可以將int main函式的程式碼簡化一下,簡化成如下
首先拿到forwarding指標然後再拿到age的值
二:__block的記憶體管理
1. 當block在棧上時,並不會對__block變數產生強引用;
2. 當block被copy到堆時
- 會呼叫block內部的copy函式
- copy函式內部呼叫_Block_object_assign函式
- _Block_object_assign函式會對__block變數形成強引用(retain)
3.當block從堆中移除時
- 會呼叫block內部的dispose函式
- dispose函式內部會呼叫_Block_object_dispose函式
- _Block_object_dispose函式會自動釋放引用的__block變數(release)
拓展:__block的_forwarding指標
棧上block的forwarding指標指向堆上的block,而堆上block的forwarding指標指向自己本身的指標。
三:迴圈引用
關於block迴圈引用的基本概念,專輯block已經講解,本篇講述核心內容
1. 解決迴圈引用問題-ARC
(1) 用__weak、__unsafe_unretained解決
下面用例子來鞏固下
int main(int argc, const char * argv[]) { @autoreleasepool { Person *person = [[Person alloc]init]; __weak Person *weakPerson = person; person.block = ^{ NSLog(@"age is %d", weakPerson.age); }; } NSLog(@"1111111"); return 0; } #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN
typedef void(^ZXYBlock)(void);
@interface Person : NSObject
@property(nonatomic,copy)ZXYBlock block; @property(assign, nonatomic)int age; @end #import "Person.h" @implementation Person -(void)dealloc { NSLog(@"%s", __func__); } @end
__weak方式解決迴圈引用問題
__unsafe_unretained方式解決迴圈引用問題
__weak,__unsafe_unretained都可以解決迴圈引用,有什麼區別呢?
結論
相同點:__weak和__unsafe_unretained都不會產生強引用
不同點:__weak指向物件銷燬時,會自動讓指標置為nil;__unsafe_unretained不安全,指向物件銷燬時,指標儲存地址 不變,如果再次訪問可能會造成野指標
(2) 用__block方式解決
下面來探究一下為什麼__block可以解決迴圈引用?看下編譯成的c++程式碼
以前結合__block 物件變數以及__block自動變數可知:c++包含了三個物件,如下
上面的三種關係如下,呼叫person = nil就是為了打斷其中一個迴圈引用鏈條,但是必須要呼叫block()
2. 解決迴圈引用問題-MRC
MRC下,首先要在編譯器上設定為MRC環境。Build Settings->Automatic Reference Counting設為No
(1) 用__unsafe_unretained解決
因為MRC下不存在弱指標,所以不存在__weak修飾解決迴圈引用
(2) 用__block解決
總結
上面是block最後一篇的講解,關於block總共有四篇部落格,應該可以講解完所有關於block的內容,應該會大大增加大家對block底層的理解,如果覺得有意義有所幫助,歡迎點贊和關注,本人會及時更新部落格!!!
&n