年年有"余"

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 124859|回复: 1

内存管理关于set方法的一个典型示例

[复制链接]
  • TA的每日心情
    奋斗
    2022-12-13 21:26
  • 签到天数: 371 天

    [LV.9]以坛为家II

    发表于 2014-3-18 23:53:19 | 显示全部楼层 |阅读模式
    本帖最后由 Sian 于 2014-3-18 23:57 编辑

    1、基本场景:对象的成员变量中包含另外的对象;
    2、成员变量在赋值时便牵涉到内存管理的细节;
    3、对象本身是内存释放时,需要对成员变量进行全部释放;

    比如创建一个Person对象,Person对象中有成员变量Car(对象),通过几张图片来说明问题:
    1、创建一个Person对象p
    002.png


    2、创建一个Car对象c1,_speed = 200
    003.png


    3、让p拥有c1对象([p setCar:c1]),此时c1的拥有者有两个,所以p在拥有c1时,需要进行一次retain操作(_car = [car retain]),此时c1的retainCount=2
    004.png


    4、再创建一个Car对象c2,为p拥有c2做准备,注意此时各对象的retainCount值
    005.png


    5、对象p想拥有c2,最直观的做法是直接将c2赋值给p的成员变量_car,但这里有一个很关键性的问题,p之前拥有了c1,并且对c1进行了retain操作,现在如果放弃c1,需要对c1进行release操作([_car release]),同时在重新拥有c2时,对c2进行retain操作(_car = [car retain]),所以p在重新拥有c2时,注意各对象的retainCount值
    006.png


    6、Car对象c1、c2都为临时对象,创建的目的都是为了为Person对象p服务,所以c1、c2创建好对象完成使命后,不应该再对创建好的Car对象一直拥有操作权,及时释放自身,所以c1与c2在完成赋值后进行release操作[c1 release] [c2 release],之后c1的retainCount=0,对象被dealloc,c2的retainCount=1,此时只有一个拥有者,即p的成员变量_car
    007.png


    7、最后,如果Person对象p自身需要释放时,一定要及时对自己所拥有的对象进行释放,即p在进行release操作时,要对当前拥有的所有对象进行release操作,由于对象被释放时会调用dealloc方法,所以一般在对象的dealloc方法中对所拥有的成员变量对象进行release操作,保证Person对象释放后,他所拥有的对象都同时被释放;

    参考代码如下:

    Person.h
    1. //
    2. //  Person.h
    3. //  Retain
    4. //
    5. //  Created by yusian on 14-3-18.
    6. //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    7. //
    8. #import <Foundation/Foundation.h>
    9. #import "Car.h"
    10. @interface Person : NSObject
    11. {
    12.     Car * _car;
    13.    
    14. }
    15. - (void)setCar:(Car *)car;
    16. - (Car *)car;
    17. @end
    复制代码

    Person.m
    1. //
    2. //  Person.m
    3. //  Retain
    4. //
    5. //  Created by yusian on 14-3-18.
    6. //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    7. //
    8. #import "Person.h"
    9. @implementation Person
    10. - (void)setCar:(Car *)car
    11. {
    12.     [_car release];
    13.     _car = [car retain];
    14. }
    15. - (Car *)car
    16. {
    17.     return _car;
    18. }
    19. - (void)dealloc
    20. {
    21.     [_car release];
    22.     NSLog(@"Person is dealloc...");
    23.     [super dealloc];
    24. }
    25. @end
    复制代码

    Car.h
    1. //
    2. //  Car.h
    3. //  Retain
    4. //
    5. //  Created by yusian on 14-3-18.
    6. //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    7. //
    8. #import <Foundation/Foundation.h>
    9. @interface Car : NSObject
    10. {
    11.     int _speed;
    12. }
    13. @property int speed;
    14. @end
    复制代码

    Car.m
    1. //
    2. //  Car.m
    3. //  Retain
    4. //
    5. //  Created by yusian on 14-3-18.
    6. //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    7. //
    8. #import "Car.h"
    9. @implementation Car
    10. - (void)dealloc
    11. {
    12.     NSLog(@"The Car of speed=%d is dealloc...", _speed);
    13.     [super dealloc];
    14. }
    15. @end
    复制代码

    main.m
    1. //
    2. //  main.m
    3. //  Retain
    4. //
    5. //  Created by yusian on 14-3-18.
    6. //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    7. //
    8. #import <Foundation/Foundation.h>
    9. #import "Person.h"
    10. int main()
    11. {
    12.     Person * p = [[Person alloc] init];
    13.    
    14.     Car * c1 = [[Car alloc] init];
    15.     c1.speed = 200;
    16.    
    17.     Car * c2 = [[Car alloc] init];
    18.     c2.speed = 300;
    19.     [p setCar:c1];
    20.     [p setCar:c2];
    21.    
    22.     [c2 release];
    23.     [c1 release];
    24.     [p release];
    25.     return 0;
    26. }
    复制代码
    运行结果:
    2014-03-18 23:51:22.626 Retain[5585:303] The Car of speed=200 is dealloc...
    2014-03-18 23:51:22.627 Retain[5585:303] The Car of speed=300 is dealloc...
    2014-03-18 23:51:22.628 Retain[5585:303] Person is dealloc...
    Program ended with exit code: 0

    过程图pptx下载:
    游客,本帖隐藏的内容需要积分高于 1 才可浏览,您当前积分为 0



  • TA的每日心情
    奋斗
    2022-12-13 21:26
  • 签到天数: 371 天

    [LV.9]以坛为家II

     楼主| 发表于 2014-3-19 07:52:56 | 显示全部楼层
    为严谨起见,setCar:方法还需要进行改进:
    1. - (void)setCar:(Car *)car
    2. {
    3.     if (car != _car) {
    4.     [_car release];
    5.     _car = [car retain];
    6.     }
    7. }
    复制代码
    这样做的目的是为了防止[p setCar:c1];反复赋值c1把Car对象传递给_car后,c1自身会释放,此时只有_car对Car有拥有权,即此时Car对象的retainCount=1,如果再进行一次[p setCar:c1]操作,会先进行[_car release](此时由于retainCount=0,对象被释放),再进行[car retain]对象已不存在。
    因此,如果同一对象反复赋值,应该直接忽略,不进行任何操作,即在方法里面加判断 if ( car != _car ) 才进行相关操作,否则不执行任何动作。
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    手机版|小黑屋|Archiver|iOS开发笔记 ( 湘ICP备14010846号 )

    GMT+8, 2024-4-28 10:14 , Processed in 0.052179 second(s), 22 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表