内存管理

来源:互联网 发布:北京网络医生招聘 编辑:程序博客网 时间:2024/06/08 16:14

对象的生命周期

1 诞生(通过alloc new方法实现)       

2 生存(接受消息并执行操作)

3 交友(通过复合以及向方法传递参数)

4 死去 (被释放掉)

引用计数

Cocoa通过采用引用计数的方式(reference counting)每个对象都有一个与之相关联的整数,被称为引用计数器,当某段代码段需要访问一个对象时,这个代码段就将保留计数器加1 当访问结束后,将该对象的保留计数器减1.当一个对象的保留计数器归0时,OC会自动向对象发送一条dealloc消息。(注意dealloc消息不能直接调用,OC会在需要销毁对象的时候自动调用它)

- (id)retain;(注意返回值类型是id 这样做的好处是 可以再接受其他消息的同时进行retain操作,增加对象的保留计数器的值并要求对象完成某种操作。例如 [[car retain] setTire:tire]) 表示要求car对象的保留计数器加1并执行setTire操作

- (void)release;

- (NSInterger)retainCount

对象所有权的问题

定义:如果一个对象(假设这个对象是car)内有指向其他对象的实例变量(假设是engine),则称该对象拥有这些对象。同样,如果一个函数(假设是main函数)创建了一个对象,则称该函数拥有该对象。

问题:对象的所有权是谁,谁负责当对象不再使用的时候向对象发送release消息 因为car可能正在使用engine,所以不可能有main函数,也有可能main函数在随后要用到engine,所以不能是car发送release

解决问题的办法:让car类保留engine对象,car类应该在setEngine:方法中保留engine对象(将其引用计数器加1 变成2)这是因为car和main两个实体都在使用engine对象,而main函数负责释放engine对象。然后当car类完成其任务后在释放engine对象(在他的dealloc方法中)最后engine被回收

由此牵引出另一个问题:访问方法中的保留与释放

访问方法中的保留与释放

- (void)setEngine:(Engine *)newEngine

{

    engine = [newEngine retain];

}//bad code 

在main函数中

Engine *engine1 = [Engine new];//count = 1

[car setEngine:engine1];// count = 2

[engine1 release];//count = 1;


Engine *engine2 = [Engine new];//count = 1

[car setEngine:engine2];//count = 2

此时出现的问题是 engine1的应用计数器还是1 不能被回收 造成内存泄露

改进1

- (void)setEngine:(Engine *)newEngine

{

    [engine release];


    engine = [newEngine retain];

}//bad code 

可以修复前一个例子的问题,但是当newEngine对象和engin(原来的)是同一个对象时,会出问题

Engine *engine = [Engine new];//engine count = 1

Car *car1 = [Car new];

Car *car2 = [Car new];

[car1 setEngine:engine];//engine count = 2

[engine release];//main函数对engine对象进行释放 count = 1


[car2 setEngine:engine];//由于engine的set方法先对engine对象进行release操作,所以engine的count = 0 ,并释放掉这块内存,所以在执行下面的操作engine = [newEngine retain];会出现错误(访问了一块bad Acess)

改进2

- (void)setEngine:(newEngine)

{

    [newEngine retain];//先保留新的engine

    [engine release];//释放

    engine = newEngine;

}   //解决

上一个问题比较好解决的原因就是因为我们知道什么时候这个对象不再使用。接下来的问题是当我们不知道什么时候不在使用一个对象时怎么办

引出下一个问题:对象的自动释放

对象的自动释放

例子:

- (NSString *)description

{

    NSString *desc;

    desc = [[NSString alloc] initWithFormat:@"i am %d years old",4];

    return desc;

}

在这个例子中我们创建了一个字符串对象,但是由谁来负责销毁它呢。首先不能是description方法 因为如果先释放掉字符串对象再返回它,则保留计数器归零 对象会马上被销毁。

可以这样做

NSString *desc = [someobject description];

....//操作

[desc release]; //但是不方便  还有更好的的方法 自动释放池

自动释放池

概念:一个用来存放对象的池子(集合),当该自动释放池要被销毁时,会向池子中的所有对象发送release消息,所有的对象的引用计数器都会减一(但不一定对象会被回收)

所以上面的例子可以这么写:

- (NSString *)description

{

    NSString *desc;

    desc = [[NSString alloc] initWithFormat:@"i am %d years old",4];

    return [desc autorelease];//加入到自动释放池

}

..............待续....

0 0
原创粉丝点击