ARC
(Automatic Reference Counting
)ARC
工作方式是在代码编译的时候,自动加入内存控制代码,来控制对象的生命周期,确保对象使用的内存空间正确的分配和释放。在ARC
中我们不能使用MRC
的关键字,例如:release,retain,autorelease
.
基本上ARC已经能解决项目中的90%的内存管理问题,但是有些循环引用还是需要我们程序员手动去释放,下面列举项目中经常出现的循环引用的问题。
1、block的循环引用
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) NSString *testString;
@property (strong,nonatomic)void (^blockTest)(NSString *);
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.blockTest = ^(NSString *string) {
self.testString = string;
};
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
编译器会提示 Capturing 'self' strongly in this block is likely to lead to a retain cycle
根据提示,我们可以肯定的是,上面的代码出现了循环引用了。
此时block强引用self,self强引用block,这样就造成了循环引用。如何打破循环引用?只需要self变弱就就好了。
备注:只要在block使用了self中的属性或者方法,就是属于block强引用了self,为什么呢? 具体看下block实现原理,因为我也不知道哈哈哈😆
__weak typeof(self) weakSelf = self
self.blockTest = ^(NSString *string) {
weakSelf.testString = string;
};
上面的解决方案能够满足我们开发的需求,但是还是有点问题,下面举个例子
classA push 到classB
@interface ClassB ()
@property (nonatomic, copy) dispatch_block_t block;
@property (nonatomic, strong) NSString *str;
@property (nonatomic, strong) ClassA *classA;
@end
@implementation ClassB
-
(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.classA = [[ClassA alloc] init];
self.classA.delegate = self;self.str = @"111";
__weak typeof(self) weakSelf = self;
self.block = ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",strongSelf.str);
});
};
self.block();
} (void)dealloc
{
NSLog(@"dealloc");
}
1、在5秒后 `pop`到`classA`,`nslog` 会打印 `null`,
2、在5秒内 `pop` 到`classA`,`nslog`会打印`1111`.
造成上面的原因很浅显了。。。。classB被dealloc,_str属性也会被release,所以就是null.
解决上面的问题
self.str = @"111";
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(self) strongSelf = weakSelf;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",strongSelf.str);
});
};
self.block();
在blcok内部,声明一个变量`strongSelf` 放在栈区,`classB`的`retainCount+1`,当`block`执行完,`strongSelf`才会被回收。此时就能解决以上问题。
2、单利模式的循环引用
代码如下
@protocol ClassADelegate <NSObject>
- (void)fuck;
@end
@interface ClassA : UIViewController
@property (nonatomic, strong) id <ClassADelegate>delegate;
@end
@interface ClassB ()
@property (nonatomic, strong) ClassA *classA;
@end
@implementation ClassB
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.classA = [[ClassA alloc] init];
self.classA.delegate = self;
}
A强引用B,B又强引用A,造成了循环引用,。修改方法如下:
`@property (nonatomic,weak) id <ClassADelegate>delegate;`
总结循环引用,只需要打破这个圈即可。