使用weak strong dance 解决 block 循环引用

Posted 芒果味ly

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用weak strong dance 解决 block 循环引用相关的知识,希望对你有一定的参考价值。

写在前面的话

使用 block 的时候很容易造成循环引用,使用 ARC 编译与否解决的办法也不一样,这里简单总结下,需要硬性的记住类型也是很烦的一件事,如果能自动推断出类型就好了,这里介绍一个保留的函数实现自动推断变量类型,最后总结出 weak strong dance 的宏。

循环引用的产生

首先看个引发循环引用的例子:


@interface Example ()

@property (nonatomic, strong) Maker *maker;

@end

@interface Maker ()

@property (nonatomic, copy) void(^cookieMaked)(int count);

@end

- (void)makeCookie

    [self.maker makeCookie:^(int count) 
        [self makeCookieSucc:count];
    ];

Example 持有了 Maker ,Maker 持有了 cookieMaked , cookieMaked 保留了 example 对象!这样就构成了闭环,造成了内存泄露!下面就来解决这个问题,不过 ARC 与否还不一样,因此分开说吧。

非 ARC 编译

这里采取不让 cookieMaked 保留 example 对象的方式打破闭环:

- (void)makeCookie

    __block Example *this = self;
    [self.maker makeCookie:^(int count) 
        [this makeCookieSucc:count];
    ];

这里 __block 的作用相当于 __unsafe_unretained ,意思是不会保留被修饰的对象,就这样解决了循环引用问题!

使用 ARC 编译

以上写法在非 ARC 下有效,但是 ARC 下是不行的!!!可以在 WWDC 2011 section 322 里找到答案,简单总结下 ARC 编译的情况:

__block 等同于默认的 __storng; 因此 ARC 下不能再使用 __block 解决 block 保留问题! 
而是使用 __weak 替代 __block ; 
如果非要使用 __block 那么需要这样写 __block __unsafe_unretained 
Example *this = self;

weak strong dance

所谓 weak strong dance 就是在 block 外部创建一个 weak 的对象,block 内部创建一个 strong 的对象,weak 目的很明显解决 block 循环引用的,strong 的意图是在 block 执行期间持有对象,保证对象的安全性:

    __weak Example *this = self;
    [self.maker makeCookie:^(int count) 
        __strong Example *self = this;
        [self makeCookieSucc:count];
    ];

推断变量类型

发现每次解决 block 循环引用问题都要定义一个类型和 self 一样的新变量,确实很麻烦,即使写个宏也要传个类型进去,很麻烦的说!后来找到了一个 GNU c函数,能够推断出变量或者表达式的类型,他就是 typeof() ;LLVM 编译器下最好还是使用__typeof(),因为编译器版本不同时有可能不识别 typeof();有了这么爽的方法后,就可以写个完美的宏了:

#define __weakself  __weak __typeof(self)__weakSelf = self;
#define __strongself __strong __typeof(__weakSelf) self = __weakSelf;

上面的 weak strong dance 将改写为:

    __weakself;
    [self.maker makeCookie:^(int count) 
        __strongself;
        [self makeCookieSucc:count];
    ];

有时候不仅仅是 self ,也可能是别的对像,因此写个通用的宏很有必要:

#define weakify(_obj)   __weak __typeof(_obj) _weak##_obj = _obj;
#define strongify(_obj) __strong __typeof(_weak##_obj) _obj = _weak##_obj;

既然有了通用宏了,那就把 weakself ,strongself 的宏改下吧:

#define __weakself  weakify(self)
#define __strongself strongify(self)

哈哈,有了这些宏,就不怕 block 带来的循环引用问题了!

以上是关于使用weak strong dance 解决 block 循环引用的主要内容,如果未能解决你的问题,请参考以下文章

循环引用 && weak strong

strong ,weak,copy关键字使用,及weak跟assign区别

iOS strong与weak的使用

强引用strong和弱引用weak的定义

strong和weak

__strong和__weak