1.并不是说block当中使用了self就一定会造成循环引用,例如使用系统的方法
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0, completion = NULL
可以这样理解,当前的self是无法持有一个类对象的。
测试方式
a.新建一个项目ViewController为根控制器,并且新建FirstVC
b.在ViewDidLoad中使用
[UIView animateWithDuration:5 animations:^{ NSLog(@"第一次打印 %@",self); }];该方法
c.由ViewController模态出FirstVC,然后FirstVC在dismiss
d.查看FirstVC中
- (void)dealloc{
NSLog(@"%s --> FirstVC -dealloc",__func__);
}
这段代码是否执行。
2.有些系统方法当中使用self,也是会造成循环引用的,例如在FirstVC中写上如下代码
在FirstVC dissmis的时候dealloc方法并不会执行,解决方式就是使用__weak typeof(self) weakSelf = self;这种方式来解决。
3.除了系统方法,在使用AFNetWoking的时候也可以在其中使用self,测试方式和上面的测试方式一样,一般我们进行的网络请求都是使用一个网络请求类,当前的self并不会持有那个类,所以不会造成循环引用,但是我又做了一个测试,那就是让当前的FirstVC中持有这个请求类对象
[[NSNotificationCenter defaultCenter] addObserverForName:@"123" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
NSLog(@"第二次打印 %@",self);
}];
发现在FirstVC dissmis的时候 dealloc方法仍然会执行,应该是AFN底层有一些特殊的处理。
4.在自己定义block的时候往往会遇见循环引用的问题,例如在FirstzVC中定义了一个block
_session = [AFHTTPSessionManager manager];
[_session POST:@"www.baidu.com" parameters:nil progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"第二次打印 %@",self.view);
}];
//这段代码是写在FirstVC中的
这段代码写在FirstVC中,如果block中使用self就会造成循环引用
如果testblock的实现写在ViewController当中,是不会造成循环引用的
5.有时会在block内部写上__strong typeof(weakSelf) strongSelf = weakSelf;这句话,这句话的作用是强引用一下这个弱指针,使其不立刻释放,在项目中具体的应用如下代码
_name = @"123";
__weak typeof(self) weakSelf = self;
_testblock = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//NSLog(@"第五次打印 %@",weakSelf.name);
NSLog(@"第五次打印 %@",strongSelf.name);
});
};
self.testblock();
这段代码写在FirstVC当中,在FirstVC dissmis的时候还没执行这个延迟函数就用到了strongSelf,如果单独使用weakSelf是打印不出来name这个属性的。