類型
1.NSGloabalBlock 全局block斥废,存儲在全局區(qū)
image.png
該block無參數(shù)井誉,無返回值贡歧,內(nèi)部也沒有引用外部變量,屬于全局block
2.NSMallocBlock 堆區(qū)block
image.png
該block會訪問外界變量探膊,會底層拷貝a杠愧,所以是堆區(qū)block
3.NSStackBlock 棧區(qū)block
image.png
該block使用__weak修飾,不進(jìn)行強(qiáng)持有逞壁,就還是棧區(qū)block流济,在開發(fā)過程中棧區(qū)block幾乎找不到
4.總結(jié):block默認(rèn)存儲在全局區(qū),如果訪問了外部變量猾担,并進(jìn)行了底層copy操作袭灯,如果是強(qiáng)引用,就是堆區(qū)block绑嘹,如果是弱引用稽荧,就是棧區(qū)block
常見問題:循環(huán)引用
- 1.原因:A引用B,B也引用A工腋,導(dǎo)致釋放不掉姨丈,就是循環(huán)引用
- 2.解決方案:
- A. weak -> strong同時使用
- B.__block修飾對象(在block內(nèi)部使用完成以后要置為nil,并且要保證block一定會執(zhí)行)
- C.把self當(dāng)成block的參數(shù)進(jìn)行傳入使用
- D.使用虛基類NSProxy
循環(huán)引用解決方案詳解
1.weak -> strong
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof (self) strongSelf = weakSelf;
NSLog(@"%@",strongSelf.name);
};
weak和strong盡量一起使用擅腰,如果單純的使用weak在某些特定的情況下會出現(xiàn)問題蟋恬,比如:
image.png
該情況self已經(jīng)被釋放,但是釋放以后還會調(diào)用self.name ,此時就會出現(xiàn)打印null的情況
2.__block修飾變量
__block ViewController *vc = self;
self.block = ^{
NSLog(@"%@",vc.name);
vc = nil;
};
注意點:使用這種方式的話趁冈,必須保證block會被調(diào)用歼争,且在內(nèi)部置空vc拜马,否則依舊會產(chǎn)生循環(huán)引用
3.將self作為參數(shù)
self.block = ^(ViewController *vc) {
NSLog(@"%@",vc.name);
};
self.block(self);
4.虛基類NSProxy
該方式再此不做詳細(xì)介紹,虛基類的使用場景除了解決循環(huán)引用沐绒,還可用于定時器NSTimer俩莽。后面文章統(tǒng)一介紹
底層原理探索
- 1.通過LLVM的前端編譯器clang編譯.c文件為.cpp文件,看c語言實現(xiàn)
- A.首先新建一個main.c文件
- B.進(jìn)入main.c所在文件夾乔遮,執(zhí)行命令:xcrun -sdk iphonesimulator clang -arch x86_64 -rewrite-objc block.c
- C.生成main.cpp文件
- 2.通過查看匯編并配合源碼探索
- A.在block內(nèi)部打個斷點扮超,通過Debug -> Debug workflow -> always show Dissasembly 查看匯編指令,找到block調(diào)用的函數(shù)名蹋肮,進(jìn)入libsystem_blocks.dylib源碼中查找探索