内存管理基本原理及非ARC环境使用小心得

最近做项目,因为要求是非ARC环境,熟悉了ARC环境后,非ARC的要求却是一个小小的挑战,不过再怎么也是一个进步的方向,为此搜集了一些资料,整理了各位大神,前辈的心得,自己整理了一篇更基础的理解。

可以让一些文件保留ARC机制,一些文件不保留:
在Build Phases,在其中Complie Sorces中选择需要ARC的文件双击,并在输入框中输入:-fobjc-arc
如果不需要ARC则输入:-fno-objc-arc 

基本原理认识(非ARC环境下):

1. Objective-C对象生成于堆之上,生成之后,需要一个指针来指向它。

ClassA *obj1 = [[ClassA alloc] init];

2.Objective-C的对象在使用完成之后不会自动销毁,需要执行dealloc来释放空间(销毁),否则内存泄露。
[obj1 dealloc];

这带来了一个问题。下面代码obj2是否需要调用dealloc
ClassA *obj1 = [[ClassA alloc] init];
ClassA *obj2 = obj1;
[obj1 hello]; // 输出hello
[obj2 hello]; // 能够执行这一行和下一行吗?
[obj2 dealloc];

不能,因为obj1和obj2只是指针,它们指向同一个对象,[obj1 dealloc]已经销毁这个对象了,不能再调用[obj2 hello]和[obj2 dealloc]; 。 obj2实际上是一个无效指针。

3. Objective-C采用了引用计数(ref count或者retain coiunt)。对象的内部保存一个数字,表示被引用的次数。例如,某个对象被两个指针所(指向)引用那么它的retain count为2.需要销毁对象的时候,不直接调用dealloc真正销毁这个对象。

4. objective-C指针赋值时,retain count不会自动增加,需要手动retain。

【如果使用了add object或是set value进行赋值,则retain count只会增加直接引用的对象,间接引用的不会操作。也就是说只会对添加的对象计数加一,并不对内层的对象加1;】

  •  一个对象的dealloc方法若想被系统自动调用,前提是拴在此对象身上的狗链子已经全部消失,即retainCount为0.(在内存管理时,不建议去人工计算retainCount大小,来判断对象是否该释放了。应该使用对象“所有权”的思想去理解内存管理)。
  • 我们知道alloc \ copy \ retain 操作会让你个对象被一个指针持有。但是,大家往往忽略对象本身self的赋值,也会被一个指针持有。如下:
self.tableView.delegate = self;                     //让self被tableView.delegate 持有,需要显示release 
  • 如果一个对象被一个指针,通过 *** = self;持有,那么应该在合适释放比较合适呢。dealloc肯定不行,因为只有对象没有持有者时系统才会进dealloc。一般地,应该写在返回按钮或其它页面跳转事件中。

viewDidUnload与dealloc的区别 【它们两个没有任何关系】

其调用时机:

viewDidUnload:只有在收到内存警告后controller连着的主View被释放才会调用。

dealloc:由系统中类销毁或是内存不足时调用,因为系统知道类何时被销毁,一般为一个对象的retainCount为0时,系统会自动调用dealloc将这个对象进行销毁。

// 更多参见:
Advanced Memory Management Programming Guide

个人理解:

当我们不想再引用这个对象时就可以使用release来释放将这个对象的引用减1,去调用release方法。当我们传值给一个方法时,其实接收的参数只是一个指针,我们要做的是将传过来的同样类型的指针地址赋值过来,这样它们拥有的是同样的一个对象,如果我们使用一个新的指针指向这个对象(赋值)那么我们就可以将参数进行一次release,不过此时要记得将这个新的指针指向的对象retain一下。这样才能保证使用正常。

对于导航控制器对象的release,我们Push或是pop时需要放到哪个位置呢,一般来说需要将其写在返回按钮或其它页面跳转事件中。

如 

ViewController *A = [ViewController alloc] init];
[self.navigationController pushViewController:A animated:YES];
[A release];

这时我们就需要将A控制器进行一次release,因为导航控制器已经将其加入到navigation controller栈中也就是说已经对其进行了引用,这时,A已经不需要对所指身的对象有所有权了,就可以将其release掉了。

口诀与范式:

1. 谁创建,谁释放(你使用alloc,copy,retain一个对象,你就要在不使用时release或autorelease一下,不是你创建的,你就不需要去释放)
解释:你在一个函数中alloc生成了一个对象,且这个对象只在这个函数中被使用,那么你就必须在这个函数中调用release或autorelease。如果你在一个class的某个方法中alloc一个成员对象,且没有调用autorelease,那么你需要在这个类的dealloc方法中调用release;如果调用了autorelease,那么在dealloc方法中什么都不需要做。

2. 除了alloc、new、copy之外的方法创建的对象都被声明了autorelease。

3. 谁retain,谁release。只要你调用了retain,无论这个对象是如何生成的,你都要调用release。有时候你的代码中明明没有retain,可是系统会默认在实现中加入retain。(这点比较含糊,苹果官方文档并不有明确表明)
release与nil,我们在release一个对象时要立即把指针清空(顺便说一句,release一个空指针是合法的,但不会发生任何事情[obj1 release]; obj1 = nil); //只是将这个指针所指向的对象的retainCount-1,然后将这个指针指向nil,因为指向了nil这个指针如果release的话是不会出现问题的。

3. 指针赋值给另一个指针

ClassA *obj2 = obj1;
[obj2 retain]; // do something
[obj2 release];
obj2 = nil;

4. 在一个函数中创建并返回对象,需要把这个对象设置为autorelease。

ClassA *Func1() {
    ClassA *obj = [[[ClassA alloc] init] autorelease];
    return obj;
}

5. 如果重写dealloc方法切记要在其中调用基类的dealloc

-(void)dealloc {
    ...
    [super dealloc];
}
6. 在一个class中创建和使用property
6.1 声明一个成员变量。 ClassB *objB;

6.2 使用property,加上retain参数; 

6.3 定义property@synthesize objB;

6.4. 除了dealloc方法以外,始终用点(.)操作符的方式来调用property  self.objB或者objA.objB; 

6.5 在dealloc方法中release这个成员变量[objB release]; 

6.6 在给这个property赋值时,有手动release和autorelease两种方式;

// 第6.2点与第6.3点,因为在使用 retain 和 @synthesize objB时自动会在set方法中

if (objB != value) {
    [objB release];
    objB = [value retain];
}
所以我们需要在dealloc方法中release这个成员变量。
- (void)dealloc{
    [objB release];
    [super dealloc];
}
7.如果只是使用类拓展声明了变量,如果将一个指针赋值给它需要记住retain一下(符合使用规则),在使用最终的dealloc方法中,记得将成员变量release一下。至于传过来的指针,其在上一个方法中建议使用autorelease方法,或者调用release方法,非copy alloc 方法来创建对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值