3. objC内存管理(<ios4.0)
来源:互联网 发布:网络调试助手 编辑:程序博客网 时间:2024/06/05 04:49
在 objC中,实例对象的内存管理是靠引用计数来进行的,当前上下文用此对象时,就加一,否则就减一,当减到零时,就析构该对象。
1 实例对象引用计数加1
1.1 在一个生命周期中,如果用alloc, new, copy来创建类对象后,那么retain的个数就会变为1,而且此生命周期要负责对此对象发送release或者autorelease消息。这是一个ObjC中默认的规则,因为,客户程序要默认你写的代码是遵循这条规则的。
1.2 在一个对象生成后,只要向其实例发送retain消息,那么,同样retainCount的个数会增加1
此条规则说起来,非常简单,实际上在编程中,存在诸多陷阱。(c++也同样存在这种情况,见Effective C++)
首先,我们来讲@property,和C#一样,ObjC编译器也同样为属性@property <porpertyA> 生成了-(void) set<propertyA>:<propertyA*> ;-(<propertyA*>) <propertyA>;两个函数。那么,set<propertyA>:<propertyA*>函数具体的生成情况,又按照@property的相关属性进行生成,这些属性可按照下表进行理解
retain/assign/copy控制生成相应版本的set<propertyA>:<propertyA*>函数体的代码生成readwrite/ readonly控制是否要生成set<propertyA>:<protertyA*>函数体atonicity/nonatomic是否在两个函数中,要添加线程同步锁
从上边的属性的描述来看,属性的生成绝对不是想当然那样的简单,如果,程序员没有十足的把握,那么,请把着看似平淡无奇实则高胜莫测的代码交给编译器去作罢。
因为,这里我们讲解retainCount,可以简单的用代码解析一下简单的retain属性。请看一下代码:
@interface Patient:NSObject@property(retain, nonatomic) NSString* Name;@end@implementation Patient@end@interface WorkContext:Patient{ Patient* patient;}@property(retain, nonatomic) Patient* patient;/*-(void) setPatient:(Patient *)patient;//属性默认生成的两个函数,-(Patient*) patient;*/-(void) assign2Patient:(Patient*) pat;//模拟(void) setPatient:(Patient*) patient;@end@implementation WorkContext@synthesize patient;/*-(void) setPatient:(Patient *)patient{ int a = 0;}-(Patient*) patient{ return nil;}*/-(void) assign2Patient:(Patient *)pat//如果自己不是很擅长维护类对象的次数,请交给编译器吧{ Patient* ptemp = patient;//防止自己赋值自己 patient = [pat retain]; [ptemp release];//和C++中不同,无需判断是否为空。}@end/**调用*/ Patient* patient1 = [[Patient alloc]init]; NSLog(@"%ld", [patient1 retainCount]); WorkContext* workcontext = [[WorkContext alloc]init]; NSLog(@"%ld",[workcontext retainCount]); workcontext.patient = patient1;//属性的赋值 NSLog(@"%ld", [patient1 retainCount]); [workcontext setPatient:patient1];//属性默认生成的set参数,同一个对象,赋值两次 NSLog(@"%ld", [patient1 retainCount]); [workcontext setPatient:[workcontext patient]];//自己向自己赋值 NSLog(@"%ld", [[workcontext patient] retainCount]); //练习2 Patient* patient2 = [[Patient alloc]init]; WorkContext* workcontext2 = [[WorkContext alloc]init]; [workcontext2 assign2Patient:patient2];//模拟赋值函数 NSLog(@"%ld",[patient2 retainCount]);
2 实例对象引用计数减1
在Objective-C和C++中,都存在一个不成文的规定,谁申请的内存还是有谁释放。这里的谁实际就是作用域,在当前的作用域中申请了内存空间,必须要在此作用域中进行释放。
这样就出问题了。
因为,在编写函数的过程中,常常会出现在一个函数中申请内存,而此内存要在函数体之外进行应用的情况,然后由调用函数体对内存进行释放。这就有悖上文提到的不成文的规定。
这样autorelease就产生了。
函数调用release或autorelease的方法来向运行时表示对象在当前的上下文中不在需要。其中,release的方法是直接减一,并判断,如果retainCount现在为零,那么就释放该对象。
autorelease是表示该实例对象,在当前的上下文中不再需要了,retainCount保持不变。待到 NSAutoreleasePool进行清理的时候,要对所有登记过的对象进行判断。如果对象的retainCount的值和登记次数相等,那么就对该对象进行释放。
实际上这两种方式没有本质上的区别,都是表示该对象在当前上下文中,不再需要。只有释放内存的时机不同。
autorelease在编程中,非常之有用。因为程序员可以用它可以表述当前的实例对象,在当前的执行上下文中,已完全没有用处了。但在其他的函数或模块,可能有用。例如,上个章节《2.objC动态绑定》代码中的@implementation PaitentCreator工厂类的作用,用来生成一个实例对象。这一点,要比C++做的要好,C++中工厂类所生成的对象,常常是由调用者去负责销毁,直接delete或调用服务代码提供的函数,无论以哪种方式,把销毁对象的任务交给客户代码,都太危险了,大大增加内存泄漏的风险。下边是对内存管理进行的测试代码
NSAutoreleasePool* pool= [[NSAutoreleasePoolalloc] init]; Patient* tempPat = [[PaitentCreatorCreatePatient] retain]; NSLog(@"the tempPat instance object retain count = %ld", [tempPat retainCount]);//2 /** */ NSMutableString* pString = [[NSMutableStringalloc]initWithString:@"Zhao^Tiegui^^^"]; NSLog(@"the current name retain count = %ld",[pString retainCount]);//1 tempPat.name = pString; NSLog(@"the current name retain count = %ld",[pString retainCount]);//2 [pString release]; NSLog(@"the current name retain count = %ld",[pString retainCount]);//1 [tempPat printOut]; /** */ NSString* tempSex = [[NSStringalloc] initWithCString:"Zhao^Tiegui"]; NSLog(@"the sex sex retain count = %ld",[tempSex retainCount]);//1 tempPat.sex = tempSex; NSLog(@"the sex sex retain count = %ld",[tempSex retainCount]);//2 [tempSex release]; NSLog(@"the sex sex retain count = %ld",[tempSex retainCount]);//1 [tempPat printOut]; NSLog(@"the tempPat retain count = %ld",[tempPat retainCount]);//2 [tempPat release]; NSLog(@"the tempPat retain count = %ld",[tempPat retainCount]);//1 [pool release]; NSLog(@"the pool retain count = %ld",[pool retainCount]);//1 NSLog(@"the tempPat retain count = %ld",[tempPat retainCount]);//1152921504606846975无效的值 [tempPat printOut];//产生异常
这里要特别的注意,在新建的类中,一定要重载dealloc函数。并且,super的dealloc要放在子类释放之后,这里和C++析构的顺序是相同的。具体原因一样,子类在析构时候,可能会调用父类的函数。所以,父类一定要后析构于子类。
- 3. objC内存管理(<ios4.0)
- ObjC: 内存管理
- ObjC内存管理推荐写法
- ObjC第三节:内存管理
- Objc内存管理之MRC
- Objc内存管理之ARC
- Objective-c与c++混编中的objc对象内存管理
- 精品 CF与OBJC在ARC下的内存管理。
- 【ObjC那点儿事儿】OC对象内存管理 MRR
- 【ObjC那点儿事儿】OC对象内存管理 ARC
- 黑马程序员——ObjC基础—内存管理
- objc使用什么机制管理对象内存(内存管理方式有哪些)
- ObjC如何通过runtime修改Ivar的内存管理方式(一)
- ObjC如何通过runtime修改Ivar的内存管理方式(二)
- ObjC如何通过runtime修改Ivar的内存管理方式(三)
- swift3.0解疑@objc
- -Objc
- -ObjC
- Ajax的一点小总结
- Mapreduce 结果写入Hbase两种方法对比
- #Pragma应用详解
- 和菜鸟一起学linux总线驱动之初识USB的数据传输方式
- DWR配置
- 3. objC内存管理(<ios4.0)
- Linux 计时
- Extjs 多选下拉框 Ext.ux.form.LovCombo默认选择及其它BUG修复版支持多选/全选/全不选ext3.x
- HDU 2457 DNA repair(AC自动机+DP)
- sqlite3自增key设定(创建自增字段)
- 新视野大学英语 第四册 翻译
- 设计模式之中介者模式
- Runaround Numbers
- FFMPEG代码研究之打开文件