__weak与__block的区别

1.由上篇文章,已经了解到,weak是可以避免循环引用的,那么__weak的作用是什么呢,答案是:也是避免循环引用的,只不过__weak一般是在使用block的时候,用来避免循环引用的。但是要注意的是,由于__weak,不持有该对象,如果在该对象已经释放了之后,再访问block的话,在block内部就无法再访问到该对象了,为了避免该情况的发生。可以在block内部,再声明一个__strong变量来指向weakObj,使外部对象既能在 block 内部保持住,又能避免循环引用的问题。
使用时,代码如下:

MyObject *obj = [[MyObject alloc] init];
    
    __weak MyObject *weakObj = obj;
    obj.block = ^{
        __strong MyObject *strongObj = weakObj;
    };

那么__block可以避免循环引用么,答案是不可以的。因为__block会持有该对象,即使超出了该对象的作用域,该对象还是会存在的,直到block对象从堆上销毁;而__weak仅仅是将该对象赋值给weak对象,当该对象销毁时,weak对象将指向nil。
2.那么__block有什么作用呢?
(1)我们知道,在使用block中,block内部是可以访问外部的变量的,但是却不能修改外部变量。如下代码:

image.png

这时候Xcode会提示x变量错误信息:Variable is not assigning (missing __block type)。
若要修改这个外部变量,__block就派上用场了,我们需要给这个变量加上__block修饰符。
(2)没有__block修饰的时候,在调用block的时候,只是在创建block的时候,直接捕获了该变量的当前值(当前值,要注意哈),而再block之后,无论如何改变这个变量的值,block内部里的这个变量的值,始终保持捕获时的值,如下代码所示:

    [super viewDidLoad];
    
    int count = 10;
    self.block = ^{
        NSLog(@"%zi",count);
    };
    count = 5;
    self.block();
}

输出结果为10,而不是5

block使用举例[56199:3675614] 10

而如果加了__block修饰符的话,__block实际是指向了变量的地址,后期该变量改变时,__block指向的变量的值也改变。
代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    __block int count = 10;
    self.block = ^{
        NSLog(@"%zi",count);
    };
    count = 5;
    self.block();
}

输出结果为:

block使用举例[56432:3683108] 5

那为什么加上__block就可以指向变量的地址了呢,且看下篇文章,下篇文章,将深入研究block的内部原理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容