首先循环引用发生的条件就是持有这个block的对象,被block里边加入的对象持有。当然是强引用。
所以UIView的动画block不会造成循环引用的原因就是,这是个类方法,当前控制器不可能强引用一个类,所以循环无法形成。
![](https://i-blog.csdnimg.cn/blog_migrate/d827d49da02fb18883565af4177b903c.png)
AFNetworking是因为人家大神自己封装了一个completionBlock,不管你传进来是啥,都给你把循环引用打破。
![](https://i-blog.csdnimg.cn/blog_migrate/ea456b9e3d3dd7b99b80f308ddf56d0f.jpeg)
AFHTTPSessionManager * manager = [AFHTTPSessionManager manager];
[manager POST:urlStr parameters:parm progress:nil success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary * _Nullable responseObject) {
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
当然在项目上一般不会直接使用AFHTTPSessionManager,会封装一层,我们先看[AFHTTPSessionManager manager], 也就是说每次都相当于 [[AFHTTPSessionManager alloc] init], 在函数中,AFHTTPSessionManager * manager是一个局部变量, 随着函数栈的调用结束,这个局部变量也就被回收了. self并没有持有manager对象.
![](https://i-blog.csdnimg.cn/blog_migrate/9649697a04d3b221692b006559fe25ef.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6a6581e89c6ada486631cf3c649694d2.png)
我们再看看Masonry 这个框架, 最常用的就是
[imageView mas_makeConstraints:^(MASConstraintMaker *make) {
}];
我们在看看Masonry是怎么实现的, 也只是把这个block当一个形参,一个局部变量,随着函数执行完成,block也随之释放. 就算block持有了self也没是了.
![](https://i-blog.csdnimg.cn/blog_migrate/85dff2d89bf813aaaae082f7e2b93c85.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6ab10b96b5b2992f46c13b4a086f0483.png)
block 为什么用copy?
一共存在3种类型的block, __NSStackBlock__(栈区block), __NSMallocBlock__(堆区block), __NSGlobalBlock__(全局区),
在MRC下,block是存在栈中,出了函数调用栈就会被回收,copy之后, block放在堆中了, 在作用域之外也可以安全的自由调用。
在ARC下, 赋值给某个变量(局部变量,全局变量都可以)后, 系统会自动的copy一次. 在ARC下, 使用copy与strong是一样的, 因为block的retain就是用copy来实现的.
官方文档: