MRC
上次blog我谈到iOS MRC内存管理的原理、原则以及出现的问题,接下来我会结合实例继续介绍在处理MRC内存管理的时候经常出现的问题:内存泄露、循环引用(retain)
一、内存泄露:
内存泄露的主要原因在于,没有遵守内存管理的原则,要么忘记release,要么release的次数少了。下面通过代码展示:
<span style="font-family:Comic Sans MS;font-size:18px;">//第一种情况
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//创建car对象
Car *car=[Car new];
}
return 0;
}</span>
分析:指针变量car存在栈区,是一个临时变量,在程序执行到其作用域({})外时会自动销毁。但是,在堆区的对象需要手动回收,而指向这片内存的指针已经被销毁,我们在这个程序结束以前,是没有办法回收该对象的内存的。这就造成了内存泄露。
<span style="font-family:Comic Sans MS;font-size:18px;"><span style="color:#000066;">//第二种情况
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//创建car对象
Car *car=[Car new];
car=nil;
[car release];
}
return 0;
}</span></span>
分析:指针变量car被重设为nil,但堆区内存并没有释放,我们也无法再次获得该对象的内存地址,造成内存泄露。<span style="font-size:18px;">//第三种情况
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//创建car对象
Car *car=[Car new];
[car retain];
[car release];
}
return 0;
}</span>
分析:对象被retain了一次或多次,但只是release了一次或少次,在出了指针的作用域后,对象无法释放。
注:对象被retain了,有时候并没有这么明显,可能在调用函数的时候被retain或copy等。
对于内存泄露,并没有一劳永逸的方法,只能靠自己的写代码的时候,多加注意,严格遵循内存管理的原则。
二、循环retain
循环引用是一个很经典的问题,我以前在学c++的时候,就遇到过,C++通过强弱指针解决这个问题,当然本质上C++的智能指针也是通过引用计数解决问题。下面我通过一个实例来看一下OC在MRC模式下如何处理这个问题。
//main.m
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Dog.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//创建人对象
Person *lele=[Person new];
//创建狗对象
Dog *wangcai=[Dog new];
//将人的狗设为