Block原理浅析,循环引用的产生方式

经常在一些面试题里面或者其他规范里面看到,block里面不能用self,否则会产生循环引用,但是为什么不能用self,循环引用是什么,如何产生的循环引用,这些总是一知半解。带着问题,查询了一些资料了解了一部分产生原因,在这做一下记录,以防自己忘掉了,如果有大神有不同意见,欢迎提出~~

1.block的内部是什么样的?

LLVM Block_private.h上block的定义如下:

/* Revised new layout. */
struct Block_descriptor {
    unsigned long int reserved;
    unsigned long int size;
    void (*copy)(void *dst, void *src);
    void (*dispose)(void *);
};


struct Block_layout {
    void *isa;
    int flags;
    int reserved; 
    void (*invoke)(void *, ...);
    struct Block_descriptor *descriptor;
    /* Imported variables. */
};

可以看出block的结构式Block_layout上的方式,实际上我们可以将它理解成为一个对象,通俗点说,一个block就是一个对象。

 

2.block的捕获变量

block会自动的捕获变量,例如:

int i = 2;
void (^bloc)(void) = ^{
    NSLog(@"%d",i);
};

创建的bloc会讲i的值拷贝到block中,就会生成如下的结构体:

struct Block_layout_imp_bloc {
    void *isa;
    int flags;
    int reserved; 
    void (*invoke)(void *, ...);
    struct Block_descriptor *descriptor;
    /* Imported variables. */

    int i;
};

这里的i是一个只读变量,因此在block中i是不可以被修改的。

如何才能让i值可以修改呢?就是在i的声明时加入__block的关键字,这样有会生成如下结构体,并且赋值到descriptor字段中:

struct Block_descriptor_imp_i {
    unsigned long int reserved;
    unsigned long int size;
    void (*copy)(void *dst, void *src);
    void (*dispose)(void *);
};

这里可以大致理解为,加了__block修饰符之后,会生成一个i变量的指针,放入到了block的对象中

3.循环引用是如何产生的

既然前面要介绍block的捕获变量,肯定是和这个有关系的。先看下如下的代码:

detailVC* dvc1 = [[detailVC alloc] init];
void (^ bloc)(void) = ^(void){
    NSLog(@"%@",dvc1);
};

根据捕获变量的方法,bloc对象会将dvc1指针拷贝到对象中,这样bloc中就含

有一个和dvc1指向地址相同的指针,因此dvc1指向的对象,引用计数器就会+1,这样就完成了bloc中包含有dvc1的引用,这样的话,如果bloc不被销毁,dvc1就不会被销毁。

此时,如果我们将这个block当作成员变量保存在dvc1中,如下:

dvc1.callback = bloc;

那么dvc1中也有了bloc的引用,这样就导致了循环引用,这两个对象谁都销毁不掉。

4.如何避免block导致的循环引用

只要将一方的指针改为弱指针就可以,将detailVC类的callback成员变量加上weak关键字,或者添加如下操作:

detailVC* dvc1 = [[detailVC alloc] init];
__weak detailVC* dvc1w = dvc1;
void (^ bloc)(void) = ^(void){
    NSLog(@"%@", dvc1w);
};

这样block拥有的dvc1的指针就是弱指针,不会影响到dvc1的销毁。

 

写这个主要是为了自己的一些学习计划,还有时间长了有个地方方便看,因为技术有限,有什么不对的地方,还望大神们指出~~

 

参考资料:

https://blog.csdn.net/u014205968/article/details/64478360

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值