Objective - C基础: 第五天 - 3.set方法内存管理

在前面, 我们对OC的内存管理基本上有了一个认识, 也知道了多个对象的内存管理是如何处理, 虽然在前面的多对象内存管理符合内存管理的原则, 其实还有一定的小bug, 今天我们就来看看如何解决这个bug.


例子:

#import <Foundation/Foundation.h>
#import "Car.h"
@interface Person : NSObject
{
    int _age;
    
    Car *_car;
}

- (void)setAge:(int)age;
- (int)age;

- (void)setCar:(Car *)car;
- (Car *)car;

@end

@implementation Person
- (void)setAge:(int)age
{
    _age = age;
}
- (int)age
{
    return _age;
}

- (void)setCar:(Car *)car
{   
    _car = [car retain];
}
- (Car *)car
{
    return _car;
}

- (void)dealloc
{
    NSLog(@"%d岁的Person被释放.", _age);
    
    [super dealloc];
}

@end

#import <Foundation/Foundation.h>

@interface Car : NSObject
{
    int _speed;
}

- (void)setSpeed:(int)speed;
- (int)speed;
@end

@implementation Car
- (void)setSpeed:(int)speed
{
    _speed = speed;
}
- (int)speed
{
    return _speed;
}

- (void)dealloc
{
    NSLog(@"速度为%d的Car对象被回收了.", _speed);
    
    [super dealloc];
}
@end

#import <Foundation/Foundation.h>
#import "Car.h"
#import "Person.h"

int main(int argc, const char * argv[])
{
    Car *c1 = [[Car alloc]init];
    
    c1.speed = 250;
    
    Person *p = [[Person alloc]init];
    
    p.age = 20;

    [p release];
    
    [c1 release];
    
    return 0;
}

这个例子和我们之前所看的多对象内存管理是一个原理, 有增有减, 一旦release之后, 所有对象都会被释放, 但如果改一下:

int main(int argc, const char * argv[])
{
    Car *c1 = [[Car alloc]init];
    
    c1.speed = 250;
    
    Person *p = [[Person alloc]init];
    
    p.age = 20;
    p.car = c1;

    [p release];
    
    [c1 release];
    
    return 0;
}


问题1. 经过了p.car = c1; 这句代码之后, 那么car的引用计数就是2, 打印的结果也就只有Person被释放.

2015-01-26 14:38:43.066 2.set方法的内存管理[4557:447362] 20岁的Person被释放.



问题2. 如果p这个对象有钱了, 需要换车:

int main(int argc, const char * argv[])
{
    Car *c1 = [[Car alloc]init];
    
    c1.speed = 250;
    
    Person *p = [[Person alloc]init];
    
    p.age = 20;
    p.car = c1;
    
    Car *c2 = [[Car alloc]init];
    c2.speed = 300;
    
    p.car = c2;
    
    [p release];
    
    [c1 release];
    
    return 0;
}

那么c1呢? c1并没有被释放, 看看下面的示意图:



虽然在现实生活中是可以一个人拥有多部车, 但在OC中, 一旦你不用一个对象就必须的释放, 否则就会引起内存泄漏的问题.


问题3. 一旦p这个对象换车了, 如果它不用新车, 也必须得对新车进行一次release, 否则也会引起内存泄漏.



针对上面的三个问题, 其实我们可以添加两句代码解决, 比如:

#import "Person.h"

@implementation Person
- (void)setAge:(int)age
{
    _age = age;
}
- (int)age
{
    return _age;
}

- (void)setCar:(Car *)car
{
    [_car release]; //对当前正在使用的车(旧车)进行release.

    _car = [car retain];
}
- (Car *)car
{
    return _car;
}

- (void)dealloc
{
    // 当人被释放了, 那么车也要被释放
    [_car release];
    
    NSLog(@"%d岁的Person被释放.", _age);
    
    [super dealloc];
}

@end


三个对象同时释放, 打印出来的结果:

2015-01-26 14:57:42.084 2.set方法的内存管理[4688:455689] 20岁的Person被释放.
2015-01-26 14:57:42.085 2.set方法的内存管理[4688:455689] 速度为250的Car对象被回收了.
2015-01-26 14:57:42.085 2.set方法的内存管理[4688:455689] 速度为300的Car对象被回收了.


但在这里还可以稍微进行一点优化, 免得以后引起一些不必要的问题:

#import "Person.h"

@implementation Person
- (void)setAge:(int)age
{
    _age = age;
}
- (int)age
{
    return _age;
}

- (void)setCar:(Car *)car
{
    if (car != _car)
    {
        [_car release]; //对当前正在使用的车(旧车)进行release.
        
        _car = [car retain]; // 对新车进行一次retain
    }

}

只有加上这个判断, 那么当你存入的对象如果和之前一样, 那么就不用做重复的操作, 不会引起不必要的问题, 比如:

int main(int argc, const char * argv[])
{
    Car *c1 = [[Car alloc]init];
    
    c1.speed = 250;
    
    Person *p = [[Person alloc]init];
    
    p.age = 20;
    p.car = c1;
    
    Car *c2 = [[Car alloc]init];
    c2.speed = 300;
    
    p.car = c2;
    
    [c1 release];
    p.car = c1;
    
    
    
    [p release];

    [c2 release];
    
    return 0;
}



好了, 这次我们就讲到这里, 下次我们继续~~

posted @ 2015-01-26 14:28  背着吉他去流浪  阅读(164)  评论(0编辑  收藏  举报