当block中涉及self
以及self的成员变量
时,就会造成循环引用问题。一般解决这类的循环引用是使用__weak
和__strong
。
案例:
// .h文件
#import <Foundation/Foundation.h>
@interface Pet : NSObject
@property (nonatomic, copy) void(^block)(void);
@end
// .m文件
#import "Pet.h"
@implementation Pet
- (instancetype)init {
if (self = [super init]) {
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf training];
};
}
return self;
}
- (void)training {
NSLog(@"pet training");
}
- (void)dealloc {
NSLog(@"pet dead");
}
@end
// ViewController文件
#import "ViewController.h"
#import "Pet.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Pet *p = [[Pet alloc] init];
p.block();
}
@end
运行结果为:
2020-03-12 14:14:56.511389+0800 sss[3705:161369] pet training
2020-03-12 14:14:56.511497+0800 sss[3705:161369] pet dead
执行了block
里面的内容,并且解决了循环引用问题。
如果block
里面的操作是同步执行的,可以省略__strong
。将Pet.m
的代码修改:
__weak typeof(self) weakSelf = self;
self.block = ^{
[weakSelf training];
};
运行结果为:
2020-03-12 14:29:54.239222+0800 sss[3751:167410] pet training
2020-03-12 14:29:54.239314+0800 sss[3751:167410] pet dead
执行了block
里面的内容,并且解决了循环引用问题。
如果block
里面的操作是异步执行的,不可以省略__strong
。将Pet.m
的代码修改:
__weak typeof(self) weakSelf = self;
self.block = ^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[NSThread sleepForTimeInterval:5];
[weakSelf training];
});
};
运行结果为:
2020-03-12 14:32:59.274722+0800 sss[3781:169249] pet dead
解决了循环引用问题,但是没有执行block
里面的内容。因为self
提前于block
执行之前释放了,ViewController
中p
提前释放了,p
就指向nil
了,weakSelf
也会被置为nil
,当休眠结束时,再执行training
方法时,实际上是向nil
发送了一个消息。此时,__strong
不能省略。
__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 training];
});
};
运行结果为:
2020-03-12 14:45:08.079523+0800 sss[3851:174924] pet training
2020-03-12 14:45:08.079750+0800 sss[3851:174924] pet dead
执行了block
里面的内容,并且解决了循环引用问题。
如果异步执行使用__strong
,weakSelf
还会随着实体被释放和置为nil
吗?将Pet.m
代码进行修改:
- (instancetype)init {
if (self = [super init]) {
__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 training];
[weakSelf eat];
});
};
}
return self;
}
- (void)eat {
NSLog(@"pet eat");
}
- (void)training {
NSLog(@"pet training");
}
执行结果为:
2020-03-12 15:01:22.362611+0800 sss[4010:182635] pet training
2020-03-12 15:01:22.362801+0800 sss[4010:182635] pet eat
2020-03-12 15:01:22.362903+0800 sss[4010:182635] pet dead
解决了循环引用问题,并且weakSelf
并没有随着实体的释放而置为nil
,可以正常调用方法。
推出结论:使用了__strong
后,strongSelf
也会持有一份weakSelf
(不是真正的持有),此时weakSelf
不会随着实体的释放而置为nil
。strongSelf
相当于block
中的局部变量,当异步操作结束后,strongSelf
会被释放,此时的weakSelf
才会被置为nil
。解决了循环引用问题,也解决了异步执行问题。
总结:
self
:是一个指向实例对象的指针,它的生命周期至少是伴随着当前的实例对象的,所以一旦它和对象之间有循环引用是无法被自动打破的。weakSelf
:__weak
能解决循环应用问题,但是在异步执行时,可能会因为实体对象释放,造成weak�Self
被置为nil
,当block
中异步执行weakSelf
的方法时,其实是向一个nil
发送消息。strongSelf
:strongSelf
也会持有一份weakSelf
(不是真正的持有),weakSelf
不会因为实体释放被置为nil
的时候,只有当局部变量strongSelf
执行完方法,出了作用域时,会随着strongSelf
一起被置为nil
,解决了循环引用问题,也解决了异步执行问题。
网友评论