ios内存管理-ARC
一、概要
iOS5后出现了ARC。那么ARC是什么呢?自动引用计数ARC是一种编译器的功能,为Objective-C对象提供了自动化的内存管理。在ARC不需要开发者考虑保留或者释放的操作,就是不用自己手动retain、release和autorelease。 当然ARC依然是基于引用计数管理内存。
二、ARC 强制新规则
ARC相对于MRC强制加了一些新的规则。
1、你不能主动调用dealloc、或者调用retain,release,retainCount,autorelease就是这些都不用你写了。也不能@selector(retain),@selector(release)这样子调用。
2、你可以实现一个dealloc方法,如果你需要管理资源而不是释放实例变量(比如解除监听、释放引用、socket close等等)。在重写dealloc后需要[super dealloc](在手动管理引用计数时才需要)。
3、仍然可以使用CFRetain,CFRelease等其它对象。
4、你不能使用NSAllocateObject或者NSDeallocateObject。
5、你不能使用C结构体,可以创建一个Objective-C类去管理数据而不是一个结构体。
6、id和void没有转换关系,你必须使用cast特殊方式,以便在作为函数参数传递的Objective-C对象和Core Foundation类型之间进行转换。
7、你不能使用NSAutoreleasePool,使用@autoreleasepool。
8、没必要使用NSZone。
三、ARC 使用新修饰符
1、__strong 强引用,用来保证对象不会被释放。
2、 __weak弱引用 释放时会置为nil
3、 __unsafe_unretained弱引用 可能不安全,因为释放时不置为nil。
4、__autoreleasing对象被注册到autorelease pool中方法在返回时自动释放。
四、内存泄漏
ARC还是基于引用计数的管理机制所以依然会出现循环引用。
五、block使用中出现循环引用
1、常见的有情况在block使用中出现循环引用
// 情况一
self.myBlock = ^{self.objc = ...;};
// 情况二
Dog *dog = [[Dog alloc] init];
dog.myBlock = ^{ // do something};
self.dog = dog;
解决方法
__weak typeof (self) weakSelf = self;
self.myBlock = ^{weakSelf.objc = ...;};
2、那么如果block内使用了self这个时候如果某一个时刻self被释放就会导致出现问题。
解决办法
__weaktypeof(self) weakSelf =self;
self.myBlock = ^{
__strongtypeof(self) strongSelf = weakSelf;
strongSelf.objc1 = ...;
strongSelf.objc2 = ...;
strongSelf.objc3 = ...;
};
使用__weak打破循环引用。__strong用来避免在使用self过程中self被释放,__strong在block后会调用objc_release(obj)释放对象。
id__strongobj = [[NSObjectalloc] init];
// clang 编译后
idobj = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(obj,@selector(init));
objc_release(obj);
两次调用objc_msgSend并在变量作用域结束时调用objc_release释放对象,不会出现循环引用问题。
3、NSTimer循环引用
主要是因为NSRunloop运行循环保持了对NSTimer的强引用,并且NSTimer的targer也使用了强引用。
来自文档NSTimer
Note in particular that run loops maintain strong references to their timers, so you don’t have to maintain your own strong reference to a timer after you have added it to a run loop.
target
The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to this object until it (the timer) is invalidated.
解决方法:
手动调用[timer invalidate]来解除持有关系,释放内存。可能会想到在dealloc方法中来手动调用,但是因为timer持有控制器,所以控制器的dealloc方法永远不会调用,因为dealloc是在控制器要被释放前调用的。在Timer Programming Topics中有特别说明。所以一般我们可以在下面这些方法中手动调用[timer invalidate]然后置为nil:
- (void)viewWillDisappear:(BOOL)animated;// Called when the view is dismissed, covered or otherwise hidden. Default does nothing
- (void)viewDidDisappear:(BOOL)animated;// Called after the view was dismissed, covered or otherwise hidden. Default does nothing