我們都知道block如果直接或者間接的使用了self,同時(shí)self又直接或間接的強(qiáng)持有block的話(huà),那么就出現(xiàn)了循環(huán)引用的問(wèn)題;出現(xiàn)這種情況我們往往就是使用weak來(lái)修飾一個(gè)弱引用來(lái)打破這個(gè)循環(huán)解決循環(huán)引用的問(wèn)題
下面從原理來(lái)解釋weak是如何解除循環(huán)引用的;這里我們可以使用clang rewrite來(lái)查看rewrite之后的代碼來(lái)加深認(rèn)識(shí)
模擬器:
xcrun -sdk iphonesimulator clang -rewrite-objc -fobjc-arc -fblocks -mios-version-min=8.0.0 -fobjc-runtime=ios-8.0.0
真機(jī):
xcrun -sdk iphoneos clang -rewrite-objc -fobjc-arc -fblocks -mios-version-min=8.0.0 -fobjc-runtime=ios-8.0.0
使用alias設(shè)置別名,避免每次都打一長(zhǎng)串指令:
終端輸入:alias rewrite-oc=‘xxxx.m’
小技巧:關(guān)閉終端,別名會(huì)失效,避免每次都設(shè)置,我們可以將設(shè)置別名添加到配置文件.bashrc中,設(shè)置好了在終端 source .bashrc即可;然后在終端的設(shè)置中可以在終端啟動(dòng)執(zhí)行指令

循環(huán)引用是如何產(chǎn)生的
測(cè)試代碼:
- (void)testBlockRetainCycle {
self.testRetainCycleBlock = ^(void){
NSLog(@"%@", self);
};
}
clang rewrite之后查看轉(zhuǎn)化之后的關(guān)鍵代碼段:
struct __BlockTest__testBlockRetainCycle_block_impl_0 {
struct __block_impl impl;
struct __BlockTest__testBlockRetainCycle_block_desc_0* Desc;
BlockTest *const __strong self;
__BlockTest__testBlockRetainCycle_block_impl_0(void *fp, struct __BlockTest__testBlockRetainCycle_block_desc_0 *desc, BlockTest *const __strong _self, int flags=0) : self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __BlockTest__testBlockRetainCycle_block_func_0(struct __BlockTest__testBlockRetainCycle_block_impl_0 *__cself) {
BlockTest *const __strong self = __cself->self; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_8j_551wkz1d1rg878kt8mg21tg40000gn_T_BlockTest_e1e0de_mi_15, self);
}
static void __BlockTest__testBlockRetainCycle_block_copy_0(struct __BlockTest__testBlockRetainCycle_block_impl_0*dst, struct __BlockTest__testBlockRetainCycle_block_impl_0*src) {_Block_object_assign((void*)&dst->self, (void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __BlockTest__testBlockRetainCycle_block_dispose_0(struct __BlockTest__testBlockRetainCycle_block_impl_0*src) {_Block_object_dispose((void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __BlockTest__testBlockRetainCycle_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __BlockTest__testBlockRetainCycle_block_impl_0*, struct __BlockTest__testBlockRetainCycle_block_impl_0*);
void (*dispose)(struct __BlockTest__testBlockRetainCycle_block_impl_0*);
} __BlockTest__testBlockRetainCycle_block_desc_0_DATA = { 0, sizeof(struct __BlockTest__testBlockRetainCycle_block_impl_0), __BlockTest__testBlockRetainCycle_block_copy_0, __BlockTest__testBlockRetainCycle_block_dispose_0};
static void _I_BlockTest_testBlockRetainCycle(BlockTest * self, SEL _cmd) {
((void (*)(id, SEL, void (*)()))(void *)objc_msgSend)((id)self, sel_registerName("setTestRetainCycleBlock:"), ((void (*)())&__BlockTest__testBlockRetainCycle_block_impl_0((void *)__BlockTest__testBlockRetainCycle_block_func_0, &__BlockTest__testBlockRetainCycle_block_desc_0_DATA, self, 570425344)));
}
可以看到
-
__BlockTest__testBlockRetainCycle_block_impl_0結(jié)構(gòu)體內(nèi)部有一個(gè)strong修飾的selfBlockTest *const __strong self; - 在結(jié)構(gòu)體初始化的時(shí)候傳遞的是self對(duì)象
- block在arc模式下strong/copy修飾會(huì)從??截惖蕉焉?,在block釋放的時(shí)候執(zhí)行dispose釋放self
由于self強(qiáng)持有block,block內(nèi)部又強(qiáng)持有self;那么就形成了環(huán),block等self dealloc才釋放,self又由于block內(nèi)部的強(qiáng)持有導(dǎo)致無(wú)法dealloc,就產(chǎn)生了循環(huán)引用
如何解決循環(huán)引用
想要解決循環(huán)引用,就是要斷開(kāi)這個(gè)相互強(qiáng)持有的關(guān)系;你可以在合適的時(shí)機(jī)將block置為nil也可以打破這種環(huán),當(dāng)然最好的方式還是使用weak的方式
測(cè)試代碼:
- (void)testWeakBreakBlockRetainCycle {
__weak typeof(self) weakSelf = self;
self.testRetainCycleBlock = ^(void){
NSLog(@"%@", weakSelf);
};
}
clang rewrite之后查看轉(zhuǎn)化之后的關(guān)鍵代碼段:
struct __BlockTest__testWeakBreakBlockRetainCycle_block_impl_0 {
struct __block_impl impl;
struct __BlockTest__testWeakBreakBlockRetainCycle_block_desc_0* Desc;
BlockTest *const __weak weakSelf;
__BlockTest__testWeakBreakBlockRetainCycle_block_impl_0(void *fp, struct __BlockTest__testWeakBreakBlockRetainCycle_block_desc_0 *desc, BlockTest *const __weak _weakSelf, int flags=0) : weakSelf(_weakSelf) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __BlockTest__testWeakBreakBlockRetainCycle_block_func_0(struct __BlockTest__testWeakBreakBlockRetainCycle_block_impl_0 *__cself) {
BlockTest *const __weak weakSelf = __cself->weakSelf; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_8j_551wkz1d1rg878kt8mg21tg40000gn_T_BlockTest_e57b64_mi_18, weakSelf);
}
static void __BlockTest__testWeakBreakBlockRetainCycle_block_copy_0(struct __BlockTest__testWeakBreakBlockRetainCycle_block_impl_0*dst, struct __BlockTest__testWeakBreakBlockRetainCycle_block_impl_0*src) {_Block_object_assign((void*)&dst->weakSelf, (void*)src->weakSelf, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __BlockTest__testWeakBreakBlockRetainCycle_block_dispose_0(struct __BlockTest__testWeakBreakBlockRetainCycle_block_impl_0*src) {_Block_object_dispose((void*)src->weakSelf, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __BlockTest__testWeakBreakBlockRetainCycle_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __BlockTest__testWeakBreakBlockRetainCycle_block_impl_0*, struct __BlockTest__testWeakBreakBlockRetainCycle_block_impl_0*);
void (*dispose)(struct __BlockTest__testWeakBreakBlockRetainCycle_block_impl_0*);
} __BlockTest__testWeakBreakBlockRetainCycle_block_desc_0_DATA = { 0, sizeof(struct __BlockTest__testWeakBreakBlockRetainCycle_block_impl_0), __BlockTest__testWeakBreakBlockRetainCycle_block_copy_0, __BlockTest__testWeakBreakBlockRetainCycle_block_dispose_0};
static void _I_BlockTest_testWeakBreakBlockRetainCycle(BlockTest * self, SEL _cmd) {
__attribute__((objc_ownership(weak))) typeof(self) weakSelf = self;
((void (*)(id, SEL, void (*)()))(void *)objc_msgSend)((id)self, sel_registerName("setTestRetainCycleBlock:"), ((void (*)())&__BlockTest__testWeakBreakBlockRetainCycle_block_impl_0((void *)__BlockTest__testWeakBreakBlockRetainCycle_block_func_0, &__BlockTest__testWeakBreakBlockRetainCycle_block_desc_0_DATA, weakSelf, 570425344)));
}
可以看到
- block內(nèi)部的結(jié)構(gòu)體
BlockTest *const __weak weakSelf;使用的是weak修飾的
由于block內(nèi)部的對(duì)于self的引用變成了weak修飾的,那么就打破了這個(gè)環(huán),解決了循環(huán)引用