weak如何解決循環(huán)引用

我們都知道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í)行指令


圖片.png

循環(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)引用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容