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