帮朋友理解 Block 和 循环引用,写了几个测试,欢迎大家也测一下。
1 、全局变量中的 Block 属性包含了 self 。
@interface Object1 : NSObject
@property (nonatomic, copy) void(^block)();
@end
@interface ViewController ()
@property (nonatomic, strong) Object1 *obj;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.obj.block = ^ {
NSLog(@"%@", self);
};
}
@end
2 、全局变量中的 Block 属性包含了 self 的全局变量。
@interface Object1 : NSObject
@property (nonatomic, copy) void(^block)();
@end
@interface Object2 : NSObject
@end
@interface ViewController ()
@property (nonatomic, strong) Object1 *obj;
@property (nonatomic, strong) Object2 *obj2;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.obj.block = ^ {
NSLog(@"%@", _obj2);
};
}
@end
3 、全局变量中的 Block 属性包含了 self 的局部变量。
@interface Object1 : NSObject
@property (nonatomic, copy) void(^block)();
@end
@interface ViewController ()
@property (nonatomic, strong) Object1 *obj;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *string = @"";
self.obj.block = ^ {
NSLog(@"%@", string);
};
}
@end
4 、全局变量中的方法中的 Block 参数包含了 self 。
@interface Object1 : NSObject
- (void)foo:(void(^)())param;
@end
@interface ViewController ()
@property (nonatomic, strong) Object1 *obj;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.obj foo:^{
NSLog(@"%@", self);
}];
}
@end
5 、全局变量中的方法中的 Block 参数包含了 self 的全局变量。
@interface Object1 : NSObject
- (void)foo:(void(^)())param;
@end
@interface Object2 : NSObject
@end
@interface ViewController ()
@property (nonatomic, strong) Object1 *obj;
@property (nonatomic, strong) Object2 *obj2;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.obj foo:^{
NSLog(@"%@", _obj2);
}];
}
@end
6 、全局变量中的方法中的 Block 参数包含了 self 的局部变量。
@interface Object1 : NSObject
- (void)foo:(void(^)())param;
@end
@interface ViewController ()
@property (nonatomic, strong) Object1 *obj;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *string = @"";
[self.obj foo:^{
NSLog(@"%@", string);
}];
}
@end
7 、 self 的 Block 属性包含了 self 。
@interface ViewController ()
@property (nonatomic, copy) void(^block)();
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.block = ^ {
NSLog(@"%@", self);
};
}
@end
8 、 self 的 Block 属性包含了 self 的全局变量。
@interface ViewController ()
@property (nonatomic, copy) void(^block)();
@property (nonatomic, strong) NSString *string;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.block = ^ {
NSLog(@"%@", _string);
};
}
@end
9 、 self 的 Block 属性包含了 self 的局部变量。
@interface ViewController ()
@property (nonatomic, copy) void(^block)();
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *string = @"";
self.block = ^ {
NSLog(@"%@", string);
};
}
@end
10 、 self 的 Block 本地变量包含了 self 。
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
void(^block)() = ^ {
NSLog(@"%@", self);
};
}
@end
11 、 self 的 Block 本地变量包含了 self 的全局变量。
@interface ViewController ()
@property (nonatomic, strong) NSString *string;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
void(^block)() = ^ {
NSLog(@"%@", _string);
};
}
@end
12 、 self 的实例方法中的 Block 参数包含了 self 。
@interface ViewController ()
@end
@implementation ViewController
- (void)foo:(void(^)())param {}
- (void)viewDidLoad {
[super viewDidLoad];
[self foo:^{
NSLog(@"%@", self);
}];
}
@end
13 、 self 的实例方法中的 Block 参数包含了 self 的全局变量。
@interface ViewController ()
@property (nonatomic, strong) NSString *string;
@end
@implementation ViewController
- (void)foo:(void(^)())param {}
- (void)viewDidLoad {
[super viewDidLoad];
[self foo:^{
NSLog(@"%@", _string);
}];
}
@end
14 、 self 的实例方法中的 Block 参数包含了 self 的局部变量。
@interface ViewController ()
@end
@implementation ViewController
- (void)foo:(void(^)())param {}
- (void)viewDidLoad {
[super viewDidLoad];
NSString *string = @"";
[self foo:^{
NSLog(@"%@", string);
}];
}
@end
15 、 self 的类方法中的 Block 参数包含了 self 。
@interface ViewController ()
@end
@implementation ViewController
+ (void)foo:(void(^)())param {}
- (void)viewDidLoad {
[super viewDidLoad];
[[self class] foo:^{
NSLog(@"%@", self);
}];
}
@end
16 、 self 的类方法中的 Block 参数包含了 self 的全局变量。
@interface ViewController ()
@property (nonatomic, copy) NSString *string;
@end
@implementation ViewController
+ (void)foo:(void(^)())param {}
- (void)viewDidLoad {
[super viewDidLoad];
[[self class] foo:^{
NSLog(@"%@", _string);
}];
}
@end
17 、 self 的类方法中的 Block 参数包含了 self 的局部变量。
@interface ViewController ()
@end
@implementation ViewController
+ (void)foo:(void(^)())param {}
- (void)viewDidLoad {
[super viewDidLoad];
NSString *string = @"";
[[self class] foo:^{
NSLog(@"%@", string);
}];
}
@end
18 、其他类中的类方法中的 Block 参数包含了 self 。
@interface Object1 : NSObject
+ (void)foo:(void(^)())param;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[Object1 foo:^{
NSLog(@"%@", self);
}];
}
@end
19 、局部对象的方法中的 Block 参数包含了 self 。
@interface Object1 : NSObject
- (void)foo:(void(^)())param;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[Object1 new] foo:^{
NSLog(@"%@", self);
}];
}
@end
1
bytelee 2015-12-17 00:55:26 +08:00
还要分情况讨论 ARC MRC 这里边的表现也不同.
PS: 如果能贴上正确结论 就更好了 |
2
vincentxue OP 竟然没有愿意尝试的,出乎预料。
|
3
ianisme 2015-12-17 10:24:16 +08:00
一般情况下系统会出警告 is likely to lead to retain cycle
所以为了避免可能的循环引用以及系统出现的所谓 likely 警告,所有的都加上 weak block 一劳永逸 |
4
cheng4741 2015-12-17 11:00:31 +08:00 1
###先说结论(欢迎指正):
* 1 2 5 7 8 会循环引用 * 3 6 9 10 11 12 13 14 不会循环引用 * 4 15 16 17 18 看方法的实现 >循环引用就是两个对象强引用。区分的时候注意下面几点就行了 1. `block`也是对象,类也是特殊的对象 2. 引用成员变量(不管是`self.string`还是`_string`)本质上和引用了`self`是一个效果。 3. 方法内局部变量跟`self`没有引用关系 4. `block`作为方法的参数时,得看这个方法的实现有没有对这个`block`强引用,如果只是调用这个`block`那就不会产生引用 |
5
cheng4741 2015-12-17 11:01:00 +08:00
额。我以为支持 markdown 呢
|
7
shanksxiao 2015-12-17 13:47:59 +08:00 1
造成循环引用的是: 1 、 2 、 7 、 8
不会循环引用的为: 3 、 6 、 9 、 10 、 11 、 12 、 13 、 14 、 15 、 16 、 17 具体看方法的实现中有无属性强引用 block 参数而定: 4 、 5 、 18 、 19 |
8
vincentxue OP 我贴个参考答案供大家拍砖。
一定会造成循环引用: 1, 2, 7, 8 一定不会造成循环引用: 3, 6, 9, 10, 11, 14, 17 视情况而定可能会造成循环引用: 4, 5, 12, 13, 15 16, 18, 19 视情况而定可能会造成循环引用,如果方法实现中有全局变量或静态变量引用了该 Block ,那么会造成循环引用。 一定不会造成循环引用,在某些情况下有可能会造成循环引用,例如第 10 题, 如果作为参数传递给 Category 方法, Category 里将此 block 用关联属性的方式添加给实例属性,这样就循环引用了。这在使用第三方库 BlockKit 的时候经常会遇到,同学们要小心。 具体判断的方法可以参考 @cheng4741 的总结。 |
9
shanksxiao 2015-12-24 09:38:40 +08:00
@vincentxue 12 、 13 、 15 、 16 、 17 你实际上已经实现了。。。
例如:+ (void)foo:(void(^)())param { } 的实现就是什么都不做,呵呵 |
10
vincentxue OP @shanksxiao 是的
|
11
shanksxiao 2015-12-25 00:40:37 +08:00
@vincentxue 换句话说 12 、 13 、 15 、 16 是不会 retain cycle 的,而非视具体情况而定。
|
12
vincentxue OP @shanksxiao 你试试用静态变量持有 block 会不会。
|
13
vincentxue OP @shanksxiao 实例方法用一个全局变量持有就好。
|
14
vincentxue OP @shanksxiao 如果你是说以目前题目的实现当然是没有循环引用的。所以我并没有说你的答案错了啊,还给你点了赞。
|
15
c447279704 2016-02-25 18:39:27 +08:00
6 也是有可能啊,谁知道里面写的啥。。。。
|