block是如何持有對(duì)象的
推薦 + 挑錯(cuò) + 收藏(0) + 用戶評(píng)論(0)
這篇文章主要會(huì)介紹 block 是如何持有并且釋放對(duì)象的。文章中的代碼都出自 Facebook 開(kāi)源的用于檢測(cè)循環(huán)引用的框架 FBRetainCycleDetector。
為什么會(huì)談到 block
可能很多讀者會(huì)有這樣的疑問(wèn),本文既然是對(duì) FBRetainCycleDetector 解析的文章,為什么會(huì)提到 block?原因其實(shí)很簡(jiǎn)單,因?yàn)樵?iOS 開(kāi)發(fā)中大多數(shù)的循環(huán)引用都是因?yàn)?block 使用不當(dāng)導(dǎo)致的,由于 block 會(huì) retain 它持有的對(duì)象,這樣就很容易造成循環(huán)引用,最終導(dǎo)致內(nèi)存泄露。
在 FBRetainCycleDetector 中存在這樣一個(gè)類 FBObjectiveCBlock,這個(gè)類的 - allRetainedObjects 方法就會(huì)返回所有 block 持有的強(qiáng)引用,這也是文章需要關(guān)注的重點(diǎn)。
- (NSSet *)allRetainedObjects {
NSMutableArray *results = [[[super allRetainedObjects] allObjects] mutableCopy];
__attribute__((objc_precise_lifetime)) id anObject = self.object;
void *blockObjectReference = (__bridge void *)anObject;
NSArray *allRetainedReferences = FBGetBlockStrongReferences(blockObjectReference);
for (id object in allRetainedReferences) {
FBObjectiveCGraphElement *element = FBWrapObjectGraphElement(self, object, self.configuration);
if (element) {
?。踨esults addObject:element];
}
}
return [NSSet setWithArray:results];
}
這部分代碼中的大部分都不重要,只是在開(kāi)頭調(diào)用父類方法,在最后將獲取的對(duì)象包裝成一個(gè)系列 FBObjectiveCGraphElement,最后返回一個(gè)數(shù)組,也就是當(dāng)前對(duì)象 block 持有的全部強(qiáng)引用了。
Block 是什么?
對(duì) block 稍微有了解的人都知道,block 其實(shí)是一個(gè)結(jié)構(gòu)體,其結(jié)構(gòu)大概是這樣的:
struct BlockLiteral {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, 。。.);
struct BlockDeor *deor;
};
struct BlockDeor {
unsigned long int reserved;
unsigned long int size;
void (*copy_helper)(void *dst, void *src);
void (*dispose_helper)(void *src);
const char *signature;
};
在 BlockLiteral 結(jié)構(gòu)體中有一個(gè) isa 指針,而對(duì) isa了解的人也都知道,這里的 isa 其實(shí)指向了一個(gè)類,每一個(gè) block 指向的類可能是 __NSGlobalBlock__、__NSMallocBlock__ 或者 __NSStackBlock__,但是這些 block,它們繼承自一個(gè)共同的父類,也就是 NSBlock,我們可以使用下面的代碼來(lái)獲取這個(gè)類:
static Class _BlockClass() {
static dispatch_once_t onceToken;
static Class blockClass;
dispatch_once(&onceToken, ^{
void (^testBlock)() = [^{} copy];
blockClass = [testBlock class];
while(class_getSuperclass(blockClass) && class_getSuperclass(blockClass) != [NSObject class]) {
blockClass = class_getSuperclass(blockClass);
}
?。踭estBlock release];
});
return blockClass;
}
Objective-C 中的三種 block __NSMallocBlock__、__NSStackBlock__ 和 __NSGlobalBlock__ 會(huì)在下面的情況下出現(xiàn):
在 ARC 中,捕獲外部了變量的 block 的類會(huì)是 __NSMallocBlock__ 或者 __NSStackBlock__,如果 block 被賦值給了某個(gè)變量在這個(gè)過(guò)程中會(huì)執(zhí)行 _Block_copy 將原有的 __NSStackBlock__ 變成 __NSMallocBlock__;但是如果 block 沒(méi)有被賦值給某個(gè)變量,那它的類型就是 __NSStackBlock__;沒(méi)有捕獲外部變量的 block 的類會(huì)是 __NSGlobalBlock__ 即不在堆上,也不在棧上,它類似 C 語(yǔ)言函數(shù)一樣會(huì)在代碼段中。
在非 ARC 中,捕獲了外部變量的 block 的類會(huì)是 __NSStackBlock__,放置在棧上,沒(méi)有捕獲外部變量的 block 時(shí)與 ARC 環(huán)境下情況相同。
非常好我支持^.^
(1) 100%
不好我反對(duì)
(0) 0%
下載地址
block是如何持有對(duì)象的下載
相關(guān)電子資料下載
- iOS17.1可能明天發(fā)布,iOS17.1主要修復(fù)哪些問(wèn)題? 377
- LinkedBlockingQueue基于單向鏈表的實(shí)現(xiàn) 115
- BlockingQueue主要屬性和構(gòu)造函數(shù) 94
- 華為全新鴻蒙蓄勢(shì)待發(fā) 僅支持鴻蒙內(nèi)核和鴻蒙系統(tǒng)應(yīng)用 719
- 蘋果手機(jī)系統(tǒng)iOS 17遭用戶質(zhì)疑 731
- iPhone12輻射超標(biāo)?蘋果推送iOS 17.1解決此事 750
- 傳華為囤積零部件 目標(biāo)明年智能手機(jī)出貨7000萬(wàn)部;消息稱 MiOS 僅限國(guó)內(nèi),小米 28208
- 蘋果推送iOS17.0.3,解決iPhone15Pro系列存在機(jī)身過(guò)熱 216
- Testin云測(cè)兼容和真機(jī)服務(wù)平臺(tái)中上線iPhone 15系列手機(jī) 208
- 利爾達(dá)推出搭載HooRiiOS的Matter模組 145