美文网首页iOS
__weak __strong

__weak __strong

作者: 说不出口的喵 | 来源:发表于2018-08-19 11:08 被阅读13次

    因此,__block和__weak修饰符的区别其实是挺明显的: 

    1.__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。 

    2.__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。 

    3.__block对象可以在block中被重新赋值,__weak不可以。 

    ARC环境中使用weak 的修饰符来修饰一个变量,防止其在block中被循环引用,而有些特殊情况下,我们在block中又使用__strong 来修饰这个在block外刚刚用__weak修饰的变量,这是因为在block中调用self会引起循环引用,而在block中需要对weakSelf进行__strong,保证代码在执行到block中,self不会被释放,当block执行完后,会自动释放该strongSelf;

    如果你的block之行不是异步之行,在显示调用testBlock.block()时,就已经执行,此时的strongSelf变量是可以省略的,如下:

    __weak typeof(self) weakSelf = self;

    self.block = ^{

          [weakSelf print];

    };

    打印结果如下

    2017-02-03 12:13:35.881 myBlock[6131:4562526] ---->print

    2017-02-03 12:13:35.883 myBlock[6131:4562526] ------>dealloc

    虽然循环引用就打破了,但是新的问题又来了。那就是会有self提前于block执行之前释放的场景,testBlock实体释放了,self就指向nil了,weakSelf也会被置为nil,等block回来时,其实在向一个nil发消息。此时就用到了strongSelf,它的作用主要是应对异步执行的block,添加异步逻辑如下:

    __weak typeof(self) weakSelf = self;

    self.block = ^{

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

            [NSThread sleepForTimeInterval:5];

            [weakSelf print];

        });

    };

    此时的执行结果如下:

    2017-02-03 12:19:14.229 myBlock[6181:4566726] ------>dealloc

    block中的语句没有执行,添加strongSelf逻辑之后:

    __weak typeof(self) weakSelf = self;

    self.block = ^{

        __strong typeof(weakSelf) strongSelf = weakSelf;

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

          [NSThread sleepForTimeInterval:5];

            [strongSelf print];

      });

    };

    2017-02-03 13:30:23.129 myBlock[6327:4593186] ---->print

    2017-02-03 13:30:23.131 myBlock[6327:4593186] ------>dealloc

    针对上面的过程,补充流程图如下:

    有人看到这里,肯定会有疑惑,这里strongSelf的引用不又像前面的self一样导致了循环引用了吗?这里需要好好解释一下:

    self是一个指向实例对象的指针,它的生命周期至少是伴随着当前的实例对象的,所以一旦它和对象之间有循环引用是无法被自动打破的;strongSelf是block内部的一个局部变量,变量的作用域仅限于局部代码,而程序一旦跳出作用域,strongSelf就会被释放,这个临时产生的“循环引用”就会被自动打破,代码的执行事实上也是这样子的。

    我们可以简单地验证一下,首先我们用到一个CoreFoundation中的一个方法CFGetRetainCount,它可以在ARC下获取retainCount,修改main函数中如下:

    @autoreleasepool

    {

        MyTestBlock *testBlock = [[MyTestBlock alloc] init];

    NSLog(@"block执行前:%lu",CFGetRetainCount((__bridgeCFTypeRef)testBlock));

        testBlock.block();

    NSLog(@"block执行后:%lu",CFGetRetainCount((__bridgeCFTypeRef)testBlock));

    }

    执行结果如下:

    2017-02-0313:49:34.465myBlock[6380:4604974] block执行前:1

    2017-02-0313:49:34.466myBlock[6380:4604974] block执行后:2

    2017-02-0313:49:39.469myBlock[6380:4605000] ---->print

    2017-02-0313:49:39.469myBlock[6380:4605000] ------>dealloc

    我们发现block执行后,testBlock对象的retainCount加了1,说明block执行时,对testBlock对象临时加了强引用,但是最终对象顺利dealloc。

    相关文章

      网友评论

        本文标题:__weak __strong

        本文链接:https://www.haomeiwen.com/subject/xccciftx.html