Objective-C 内存管理

fen3t

贡献于2013-10-02

字数:0 关键词: Objective-C开发 Objective-C

OC内存管理 11年7月14日星期四 ios需要开发者管理内存 很高高级语言都有垃圾回收机制,但 ios开发却 没有垃圾回收机制。 虽然 ios没有垃圾回收机制,但是 mac os有垃圾 回收机制。 ios没有垃圾回收机制是因为它没有能力做垃圾 回收吗? ios将内存管理的任务交给了开发者。 11年7月14日星期四 所有权机制 (1) 在 OC中,对象不断的被其它创建、使用和销毁 为了保证程序不产生额外的内存开销,当对象 不再被需要以后,应当被立即销毁。 拥有对一个对象的使用权,我们称为是 ”拥 有 ”这个对象。 对象的拥有者个数至少为 1,对象才得以存在, 否则它应当被立即销毁。 11年7月14日星期四 所有权机制 (2) 为了确定你 (一个对象 )何时具有对另外一个对象 的所有权,以及明确对象所有者的权利和义 务, Cocoa设立了一套标准。 只有当你对一个对象做了 alloc,copy和 retain等 操作之后,你才拥有它的所有权。 当你不再需要这个对象的时候,你应该释放你 对它的所有权。 千万不要对你没有所有权的对象进行释放。 11年7月14日星期四 引用计数 Cocoa中提供了一个机制来实现上面提到的这个 逻辑模型,它被称为 ”引用计数 ”。 每个对象都有一个引用计数 (retainCount),对象 被创建的时候引用计数为 1; 当引用计数值为 0的时候,对象将被系统销毁。 11年7月14日星期四 引用计数 Cocoa中提供了一个机制来实现上面提到的这个 逻辑模型,它被称为 ”引用计数 ”。 每个对象都有一个引用计数 (retainCount),对象 被创建的时候引用计数为 1; 当引用计数值为 0的时候,对象将被系统销毁。 11年7月14日星期四 dealloc方法 dealloc方法会在对象引用计数为 0的时候被系统调用。 dealloc不要手动调用,而是让系统自动调用 (对象引用计数为 0 时 ); 对象释放的时候需要把自己所包含的对象变量也一并释放掉。 -(void) dealloc{ [name release]; [super dealloc]; } 在 dealloc方法中对变量的释放顺序应与初始化的顺序相反,最后 调用 [super dealloc]; 11年7月14日星期四 内存管理 alloc:为一个新对象分配内存,并且它的引用计数为 1。 调用 alloc方法,你便有对新对象的所有权。 copy:制造一个对象的副本,改副本的引用计数为 1,调 用者具有对副本的所有权。 retain:使对象的引用计数加 1,并且获得对象的所有 权。 release:使对象的引用计数减 1,并且放弃对象的所有 权。 autorelease:也能使对象的引用计数减 1,只不过是在未 来的某个时间使对象的引用计数减 1。 11年7月14日星期四 示例 1 使用 alloc创建对象,则需要在使用完毕后进行 释放。 Person *person1 = [[Person alloc] initWithName:@”张三 ”]; NSLog(@”name is %@”,person1.name); // 假设从这往后,我们一直都不使用 person1 了,应该把对象给释放了。 [person1 release]; 11年7月14日星期四 示例 2 Person *person2 = [Person alloc] initWithName:@”李四 ”]; NSString *name = person2.name; NSLog(@”%@”,name); // 假设从这以后,我们也不使用 person2了。 [person2 release]; 我们不应该释放 name,因为 name是我们间接获 得的,所以没有它的所有权,也不应该对它进 行释放。 11年7月14日星期四 便利构造器的管理 有时我们会通过便利构造器来获得一个新的对 象,由便利构造器产生的对象不应当由使用者 销毁,而是由便利构造器本身完成。 便利构造器通过在实现中调用 autorelease来实 现上述功能。 11年7月14日星期四 错误示例 1 +(id) personWithName:(NSString *)aName { Person *person = [[Person alloc] initWithName:aName]; return person; } 它是错误的,因为它返回了新创建的对象以 后,类就失去了释放这个对象的机会。 11年7月14日星期四 错误示例 2 +(id) personWithName:(NSString *)aName { Person *person = [[Person alloc] initWithName:aName]; [person release]; return person; } 它也是错误的,因为在返回对象的时候,对象 已经被销毁,从而不能使用了。 11年7月14日星期四 正确示例 +(id) personWithName:(NSString *)aName { Person *person = [[Person alloc] initWithName:aName]; [person autorelease]; return person; } 它是正确的,因为对新对象的销毁延迟进行, 从而使用者有时间去使用它,而不必对对象的 释放负责。 11年7月14日星期四 简单的使用示例 使用便利构造器创建对象,则使用完毕后不需 要进行释放。 -(void) printHello { NSString *str = [NSString stringWithFormat:@”Hello”]; NSLog(@”%@”,str); } 11年7月14日星期四 设置器、访问器内存管理 以下是一个经典的把内存管理结合在设置器中 的实现: 接口文件 @interface Person : NSObject{ NSString *name; } 11年7月14日星期四 设置器的实现 在设置器中,保持对新传入对象的所有权,同 时放弃旧对象的所有权。 -(void) setName:(NSString *) aName{ if(name != aName){ [name release]; name = [aName retain];//or copy } } 11年7月14日星期四 访问器的实现 在访问器中,不需要 retain或 release. -(NSString *)name{ return name; } 11年7月14日星期四 示例 用访问器获得的对象,使用完毕后不需要释 放。 -(void) printName{ NSString *name = person.name; NSLog(@”%@”,name); } 11年7月14日星期四 内存管理的常见错误 1 为使用设置器 -(void) reset{ NSString *newName = [[NSString alloc] initWithFormat:@”theNew”]; name = newName; [newName release]; } 注意: name是实例变量 11年7月14日星期四 内存管理常见错误 2 内存泄露 -(void) reset{ NSString *newName = [[NSString alloc] initWithFormat:@”theNew”]; [self setName:newName]; } 少了一次释放,导致内存泄露 11年7月14日星期四 内存管理常见错误 3 释放了没有所有权的对象 -(void) reset{ NSString *newName = [NSString stringWithFormat:@”theNew”]; [self setName:newName]; [newName release]; } 便利构造器已经为 newName设置了 autorelease, newName便没有权利和义务再去 release,下次再来访问这个变量的时候一定会 出现运行错误。 11年7月14日星期四 原则总结 凡是你通过 retain、 alloc、 copy等手段获得了所有权的对 象,都必须在你不再使用的时候,由你来调用 release、 autorelease等手段进行释放。 在一定的代码断内,对同一个对象所做的 copy、 retain和 alloc的操作次数应当与 release、 autorelease的操作次数相 等。 可以在类的 dealloc方法中释放你占有的实例变量。 对于便利构造器和访问器来说,你没有通过上面的这些手段 获得对象的所有权,因此在这些情况下你无需对获得的对象 进行额外的释放操作。 autorelease只是意味着延迟发送一条 release消息。 11年7月14日星期四 作业 检查以前的作业有没有内存管理方面的问题, 有的话给予改正。 SDK里面有一个 Instrument工具,可以检测内 存泄露,查阅资料学习一下 (google或者进博看 论坛 )。 11年7月14日星期四

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享文档获得金币 ] 1 人已下载

下载文档

相关文档