ARC虽然是自动引用计数,但我们在进行ARC开发的时候也需要注意一些问题如一下四点:
一.ARC下需要注意:
1.在ARC下使用音频播放器来播放音乐的时候,要注意要将AVAudioPlayer声明成属性,来提高播放器的声明周期,要不然是不会进行音乐播放的
// *1.在ARC播放音频文件的时候,记得提高音频播放器的生命周期
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"小苹果" ofType:@"mp3"];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
[_audioPlayer play];
2.
在使用KVO的时候,我们要把观察者声明成属性,要不然会系统崩溃,访问一块坏的内存,因为观察者要持续观察被观察者属性的变化,而ARC是编译器自己在
适合的地方为我们加上release进行内存管理,观察者对象的释放不由我们控制,我们仍然要把观察者声明成属性,来提高观察者对象的声明周期,让观察者
对象不能提前释放
// *2.KVO使用的时候
self.secVC = [[SecondViewController alloc] init];
[self addObserver:_secVC forKeyPath:@"lanouNumber" options:NSKeyValueObservingOptionNew context:NULL];
3.ARC下也需要注意内存的循环引用问题,循环引用就是两个对象相互引用,导致两个对象的内存都没有办法释放,从而引起内存泄露
// 3.循环引用现象
// teacher:1
Teacher *teacher = [[Teacher alloc] init];
// student:1
Student *student = [[Student alloc] init];
// student:2
teacher.stu = student;
// teacher:2
student.tea = teacher;
// 解决arc下循环引用问题:
// 弱化其中任何一个强引用属性,打破强引用链,在当前的例子中就是在Teacher类中将student的属性变化weak
// weak,也可以使用assign
// weak修饰对象类型,不能修饰基础类型,assign可以修饰对象类型,也可以修饰基础类型,区别:weak修饰的属性在dealloc之后,会进行安全处理,将该属性自动赋值为nil
4.arc下block的循环引用及解决方案
// 4.arc下block的循环引用
// arc下出现block的循环引用,解决方案:在block中使用__weak修饰的变量
Teacher *tea = [[Teacher alloc] init];
Teacher *teacher = tea;
// 下面的使用方式,就会出现循环引用现象
[tea setMyBlock:^{
NSLog(@"%@", teacher);
}];
解决方法:
在变量将要被引入到block块中之前,在ARC下添加__weak关键字,MRC下使用__block关键字
__weak Teacher *teacher = tea;
二. 程序受到内存警告之后的处理
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
// 1.用来判断当前控制器的视图有没有被加载过
// 2.我们可以通过这个属性来判断当前这个view有没有在window上显示
if (self.isViewLoaded && !self.view.window) {
// 1.我们可以把一些强引用属性赋值为nil
// 2.我们可以把当前控制器的view置为nil,用来节省内存,我们再次切换到这个控制器的时候,系统会自动再次触发loadView方法帮助我们创建view
// 释放声明的强引用属性
self.lanouNumber = nil;
self.audioPlayer = nil;
self.secVC = nil;
// 将控制器的view置为nil,因为控制器的view没有在window上显示,节省资源
self.view = nil;
NSLog(@"rootView dead");
}
}
三.ARC下autoreleasepool的使用
ARC
下使用NSThread创建的子线程,在子线程中执行的方法中,系统并没有为我们创建自动释放池,所以一些autorelease的属性不能及时释放,当
我们写到了release/retain等方法, ARC 下你不能写这些方法,但ARC
会帮你在合适的地方插入这些方法。这将导致内存的延迟释放。autoreleasepool是为了 autorelease
这个方法,在对象的创建者没法销毁对象的时候,可以使用autorelease让autoreleasepool每隔一段时间检查该对象的引用计数,如果
为0则释放对象。那么多个autoreleasepool的作用就是增加这种间隔,比原本autorelease释放的时间更早释放。
所以无论在ARC还是MRC我们使用NSThread的时候,方法中需要加入自动释放池
// NSThread
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction:) object:nil];
// 手动开启
[thread start];
// 就是在子线程中去执行的方法
- (void)threadAction:(NSThread *)sender
{
// 我们无论在ARC下还是MRC,在NSThread方法中都需要我们把新增的对象类型放到autoreleasepool。
// *因为NSThread开辟子线程中并没有自动释放池,没有办法对autorelease修饰的类型进行释放
@autoreleasepool {
NSLog(@"-----%d", [NSThread isMainThread]);
Teacher *teacher = [[Teacher alloc] init];
}
}