Block循环引用之weak&strong


2016/8/28 iOS

在 ARC 环境下,我们会使用 _weak 修饰符来修饰一个变量防止其在 block 中被循环引用,特殊情况下还会在 block 中使用 _strong 修饰符来修饰这个变量如下:

__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
  __strong __typeof(weakSelf)strongSelf = weakSelf;
  strongSelf.networkReachabilityStatus = status;
  if (strongSelf.networkReachabilityStatusBlock) {
    strongSelf.networkReachabilityStatusBlock(status);
  }
};
1
2
3
4
5
6
7
8

这是因为在 block 中调用 self 会引起循环引用,同时在 block 中需要对 weakSelf 进行 strong 操作,保证 self 不会被释放,当block执行完会自动释放该 strongSelf。但实际上 strong 是为了防止野指针,而 block 里大部分是用 weakSelf 访问 self 的属性,而不是局部变量,我们也不可能主动释放 self,这样看来就没有 strong 的必要了当然不排除有特殊情况。

除开上面这种一般写法,我们看看 YYKit 中是怎么使用 weak&strong

#ifndef weakify
    #if DEBUG
        #if __has_feature(objc_arc)
        #define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
        #else
        #define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
        #endif
    #else
        #if __has_feature(objc_arc)
        #define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
        #else
        #define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
        #endif
    #endif
#endif

#ifndef strongify
    #if DEBUG
        #if __has_feature(objc_arc)
        #define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
        #else
        #define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
        #endif
    #else
        #if __has_feature(objc_arc)
        #define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
        #else
        #define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
        #endif
    #endif
#endif

/**
 Example:
    @weakify(self)
    [self doSomething^{
        @strongify(self)
        if (!self) return;
        ...
    }];
 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

还有来自 libextobjc的这种写法:

#define weakify(...) \\
    autoreleasepool {} \\
    metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)

#define strongify(...) \\
    try {} @finally {} \\
    _Pragma("clang diagnostic push") \\
    _Pragma("clang diagnostic ignored \\"-Wshadow\\"") \\
    metamacro_foreach(rac_strongify_,, __VA_ARGS__) \\
    _Pragma("clang diagnostic pop")
1
2
3
4
5
6
7
8
9
10

其中细节可以参考这篇文章 http://www.jianshu.com/p/3d6c4416db5e

上次更新: 10/24/2019, 12:39:39 AM