關(guān)于block的上一篇文章Block內(nèi)部實(shí)現(xiàn)
__weak巫击、__strong、__block修飾Block的內(nèi)部實(shí)現(xiàn)原理
一. 先看一下被__block修飾的對(duì)象類型數(shù)據(jù)結(jié)構(gòu)
__block Person *person = [[Person alloc] init];
Person對(duì)象被包裝成了以下這種數(shù)據(jù)結(jié)構(gòu):
struct __Block_byref_person_0 {
void *__isa;
__Block_byref_person_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
MJPerson *__strong person;
};
可看到含有這兩個(gè)函數(shù)__Block_byref_id_object_copy
精续、__Block_byref_id_object_dispose
坝锰,是block用來(lái)處理block對(duì)這個(gè)對(duì)象的持有情況的。__block修飾基本數(shù)據(jù)類型是不會(huì)有這兩個(gè)函數(shù)的重付。
- 當(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)
了解了這個(gè)下面會(huì)用得到帽芽。
二. 在ARC下解決循環(huán)引用可以使用以下三種方法。
1. 使用__weak
推薦使用翔冀。在weak修飾的對(duì)象內(nèi)存被釋放的時(shí)候导街,weak修飾的對(duì)象會(huì)自動(dòng)置為nil。
__weak typeof(self) weakSelf = self;
self.block = ^{
NSLog(@"%p", weakSelf);
};
2. 使用__unsafe_unretained
不推薦使用纤子。如果被修飾對(duì)象內(nèi)存釋放以后訪問(wèn)該對(duì)象會(huì)報(bào)野指針錯(cuò)誤搬瑰。
__unsafe_unretained typeof(self) weakSelf = self;
self.block = ^{
NSLog(@"%p", weakSelf);
};
以上兩種循環(huán)引用示意圖如下:
3. 使用__block解決(必須要調(diào)用block)
不推薦使用。如果該block沒(méi)有被調(diào)用控硼,存在內(nèi)存泄漏風(fēng)險(xiǎn)泽论。
__block id weakSelf = self;
self.block = ^{
NSLog(@"%p", weakSelf);
weakSelf = nil;
};
self.block();
第三種循環(huán)引用示意圖如下:
三. 在MRC下解決循環(huán)引用可以使用以下兩種方法。
1. 使用__unsafe_unretained
__unsafe_unretained typeof(self) weakSelf = self;
self.block = ^{
NSLog(@"%p", weakSelf);
};
2. 使用__block
這種情況能夠解決循環(huán)引用是因?yàn)槲恼马敳拷忉屃?code>__block修飾的對(duì)象類型數(shù)據(jù)結(jié)構(gòu)卡乾。在MRC下_Block_object_assign不會(huì)對(duì)持有對(duì)象執(zhí)行retain操作翼悴。所以默認(rèn)就是弱引用。
__block id weakSelf = self;
self.block = ^{
NSLog(@"%p", weakSelf);
};
四. block在修改NSMutableArray時(shí)幔妨,需不需要添加__block抄瓦?
如圖所示:
NSMutableArray *array = [NSMutableArray array];
void (^block)(void) = ^{
[array addObject:@10];
};
這種情況是不會(huì)報(bào)錯(cuò)的,因?yàn)闆](méi)有修改array的指向陶冷,只是使用了array而已。所以不需要添加__block毯辅。