iOS经典讲解之Objective-C关联对象的内存管理
2015-09-26 16:39
501 查看
@关联对象的内存管理:
如果两个或者两个以上的对象存在关联,那么在内存管理方面要比一个对象的内存管理复杂一些,下面通过一个简单的例子来讲解一下关联对象的内存管理问题:
创建一个Pet(宠物)类:
然后创建对象进行测试测试:
此时你运行会发现Person对象已经释放但是Pet对象没有被释放,存在内存问题(内存泄露)
怎么解决哪?如果Person对象释放之后,Pet对象就没有存在的价值了,所以说,在Person对象释放的时候,就应该将Pet对象释放掉,没错,Person对象释放会调用dealloc方法,此时在dealloc方法中将Pet对象释放是最恰当的。
所以在Person类的dealloc方法中添加一句即可,如下:
情况二 :上面是通过初始化方法直接给Person对象实例变量赋值,如果通过其他方法赋值时比如set方法对其赋值时的内存怎么处理哪,下面通过一个例子来了解一下:
通过测试来解决上面思考的问题:
解决方法1、(不合理方法)
// 为了不出现重复释放问题,可以在赋值的时候将对象的引用计数加一
// 比如
你会发现在测试时,也会出现问题,比如通过set方法对其重新赋值时:
此时会出现内存泄露问题,因为retain过两次,而dealloc方法中只释放一次,所以上面解决方法不合理。
解决方法2、(不合理方法)
为了不出现上面内存泄露问题,可以在赋值之前先将原来的释放掉:如
当我们对其赋同样的值时会出现重复操作问题:
如:
解决方法3、(合理方法)
注意:在实例变量未赋值之前释放是没有问题的,对nil,做release操作相当于对着空气说话,没有任何反应。
如果两个或者两个以上的对象存在关联,那么在内存管理方面要比一个对象的内存管理复杂一些,下面通过一个简单的例子来讲解一下关联对象的内存管理问题:
创建一个Pet(宠物)类:
#import <Foundation/Foundation.h> @interface Pet : NSObject { // 无实例变量</span> } // 声明一个行为方法</span> - (void)play; @end
#import "Pet.h" @implementation Pet // 简单实现 -(void)play { NSLog(@"play......"); } // 重写dealloc方法,判断对象是否释放 -(void)dealloc { NSLog(@"宠物已经被释放"); [super dealloc]; } @end然后创建一个Person类,此类的对象可以拥有宠物,从而建立两个对象的关联关系:
#import <Foundation/Foundation.h> #import "Pet.h" @interface Person : NSObject { // Person对象拥有宠物 Pet *_pet; } // 声明一个方法用来测试 - (void)test; @end
#import "Person.h" @implementation Person // 重写初始化方法 -(instancetype)init { self = [super init]; if (self) { // 在初始化对象时创建一只宠物 // 思考:此时的Pet对象在哪释放比较得当 _pet = [[Pet alloc] init]; } return self; } // 实现测试方法 -(void)test { // 在宠物对象已经创建出来的情况下,执行方法 if (_pet) { [_pet play]; } } // 重写初始化方法 检测Person对象是否被释放 -(void)dealloc { NSLog(@"已经释放"); [super dealloc]; } @end
然后创建对象进行测试测试:
// 创建一个Person对象 同时也创建了一个Pet对象 Person *person = [[Person alloc] init]; // 执行测试方法 [person test]; // 根据内存管理黄金原则 释放对象 [person release];
此时你运行会发现Person对象已经释放但是Pet对象没有被释放,存在内存问题(内存泄露)
怎么解决哪?如果Person对象释放之后,Pet对象就没有存在的价值了,所以说,在Person对象释放的时候,就应该将Pet对象释放掉,没错,Person对象释放会调用dealloc方法,此时在dealloc方法中将Pet对象释放是最恰当的。
所以在Person类的dealloc方法中添加一句即可,如下:
-(void)dealloc { // 添加 [_pet release]; NSLog(@"已经释放"); [super dealloc]; }
情况二 :上面是通过初始化方法直接给Person对象实例变量赋值,如果通过其他方法赋值时比如set方法对其赋值时的内存怎么处理哪,下面通过一个例子来了解一下:
#import <Foundation/Foundation.h> #import "Pet.h" @interface Person : NSObject { Pet *_pet; } // 声明set方法 - (void)setPet:(Pet *)pet; - (void)test; @end
#import "Person.h" @implementation Person // 实现set方法 -(void)setPet:(Pet *)pet { // 思考:此时的写法是否存在内存问题? _pet = pet; } -(void)test { if (_pet) { [_pet play]; } } -(void)dealloc { // 当Person对象释放时,将其拥有的宠物释放掉 [_pet release]; [super dealloc]; } @end
通过测试来解决上面思考的问题:
// 创建Person对象 Person *man = [[Person alloc] init]; // 创建Pet对象 Pet *pet = [[Pet alloc] init]; // 通过set方法给Person对象的实例变量赋值 [man setPet:pet]; [man test]; // 根据内存释放原则 释放掉上面alloc出来的对象 [man release]; [pet release];运行你会发现程序崩溃,原因是什么呢?原因是在Person对象释放时,会释放掉Pet对象,而Pet对象在外面已经释放过一次,就会出现过度释放问题,导致程序崩溃。
解决方法1、(不合理方法)
// 为了不出现重复释放问题,可以在赋值的时候将对象的引用计数加一
// 比如
-(void)setPet:(Pet *)pet { _pet = [pet retain]; }
你会发现在测试时,也会出现问题,比如通过set方法对其重新赋值时:
// 创建Person对象 Person *man = [[Person alloc] init]; // 创建Pet对象 Pet *pet = [[Pet alloc] init]; // 通过set方法给Person对象的实例变量赋值 [man setPet:pet]; // 创建第二个Pet对象 Pet *pet2 = [[Pet alloc] init]; // 对Person对象实例变量重新赋值 [man setPet:pet2]; [man test]; // 根据内存释放原则 释放掉上面alloc出来的对象 [man release]; [pet release]; [pet2 release];
此时会出现内存泄露问题,因为retain过两次,而dealloc方法中只释放一次,所以上面解决方法不合理。
解决方法2、(不合理方法)
为了不出现上面内存泄露问题,可以在赋值之前先将原来的释放掉:如
-(void)setPet:(Pet *)pet { [_pet release]; _pet = [pet retain]; }同样会出现问题:
当我们对其赋同样的值时会出现重复操作问题:
如:
// 创建Person对象 Person *man = [[Person alloc] init]; // 创建Pet对象 Pet *pet = [[Pet alloc] init]; // 通过set方法给Person对象的实例变量赋值 [man setPet:pet]; // 对Person对象实例变量再次赋同样的值 [man setPet:pet]; [man test]; // 根据内存释放原则 释放掉上面alloc出来的对象 [man release]; [pet release];此时没有必要再release和retain,需要对上面的操作再完善一下:
解决方法3、(合理方法)
-(void)setPet:(Pet *)pet { if (_pet != pet) { [_pet release]; _pet = [pet retain]; } }这是最完善的操作方法,类似于属性的内存管理。
注意:在实例变量未赋值之前释放是没有问题的,对nil,做release操作相当于对着空气说话,没有任何反应。
相关文章推荐
- Object Identification #Facebook Relay文档翻译#
- structure-object structure-object-pointer
- Objective-C 分数加减乘除
- Halcon对象Hobject转换为.net对象Bitmap
- 【IOS 开发学习总结-OC-20】★★★objective-c面向对象——协议(protocol)
- org.springframework.orm.hibernate3.HibernateSystemException: a different object with the same identi
- 【IOS 开发学习总结-OC-19】★★objective-c面向对象之——类别与扩展
- NSObject的描述(+description)方法和对象的描述(-description)方法,NSLog默认输出的修改(后知后觉)
- Objective-C 基础知识之 (十八):Copy NSString的Copy现象
- Objective-C 基础知识之 (十七):内存管理原则二
- Objective-C 基础知识之 (十六):内存管理原则一
- Objective-C 基础知识之 (十五):KVC
- Objective-C 基础知识之 (十四):属性 Property 点语法
- Objective-C 基础知识之(十三):类目、延展、协议、代理等的基本概念
- Objective-C 基础知识之(十二):NSDate
- Objective-C 基础知识之(十一):Block
- iOS经典讲解之Objective-C内存管理基础知识及内存管理黄金原则
- JDK源码阅读之Object类
- 《Objective-C入门 》 第一篇 - 合成存取器
- core foundation与objective-c之间有什么关系和区别