7. 内存管理
来源:互联网 发布:html5音乐播放器源码 编辑:程序博客网 时间:2024/06/05 15:29
1.Cocoa采用了一种叫做引用计数(reference counting)的技术,有时也叫做保留计数。每个对象都有一个与之相关联的整数,被称作它的引用计数器或保留计数器。当某段代码需要访问一个对象时,该代码就将该对象的保留计数器值加1,表示“我要访问该对象”。当这段代码结束访问时,将对象的保留计数器减1,表示不再访问该对象。当保留计数器的值为0时,表示不再有代码访问该对象了,因此它将被销毁,其占用的内存被系统回收以便重用。
当使用alloc、new方法或者通过copy消息创建一个对象时,对象的保留计数器值被置为1.要增加对象保留计数器的值,可以给对象发送一条retain消息。要减少的话,可以给对象发送一条release消息。
当一个对象因其保留计数器归0而即将被销毁时,Objective-C会自动向对象发送一条dealloc消息。一定不要直接调用dealloc方法,objective-C会在需要销毁对象时自动调用它。
要获得保留计数器当前的值、可以发送retainCount消息。下面是retain、release和retainCount的方法声明。
- (id) retain;
- (oneway void) release;
- (NSUInteger) retainCount;
2.自动释放
NSObject类提供了一个叫做autorelease的方法:
- (id) autorelease;该方法预先设定了一条会在未来某个时间发送的release消息,其返回值是接收这条消息的对象。当给一个对象发送autorelease消息时,实际上是将该对象添加到了自动释放池中。当自动释放池销毁时,会向该池中的所有消息发送release消息。
2.1自动释放池创建的两种方法:
(1)、通过@autoreleasepool关键字。
(2)、通过NSAutoreleasePool对象。
当使用@autorelease{}时,所有在花括号里的代码都会被放入这个新池子里。当程序运算是内存密集型的,可以使用这种自动释放池。任何在花括号里定义的变量在括号外就无法使用了。
第二种更加明确的方法就是使用NSAutoreleasePool对象。当时用这个方法时,创建和释放NSAutorelease对象之间的代码就会使用这个新的池子。
NSAutoreleasePool *pool;
pool = [NSAutoreleasePool new];
...
[pool release];
2.2Cocoa的内存管理规则
当使用new、alloc或copy方法创建一个对象时,该对象的保留计数器的值为1。当不使用该对象时,应该发送一条release或autorelease消息。这样,该对象将在其使用寿命结束时被销毁。
当通过其他方法获得一个对象时,假设该对象的保留计数器的值为1,而且已经被设置为自动释放,那么你不需要执行任何操作来确保该对象得到清理。如果打算在一段时间内拥有该对象,则需要保留它并确保在完成时释放它。
2.3自动引用计数
如果保留了某个对象,就需要释放或自动释放该对象。必须保持retain方法额release方法的使用的词数相等。
在IOS中无法使用垃圾回收,苹果公司的解决方案被称为自动引用计数(automatic reference counting,ARC)。ARC不是垃圾回收器。垃圾回收器在运行时工作,通过返回的代码来定期检查对象。与此相反,ARC实在编译时进行工作。它在代码中插入了合适的retain和release语句,就好像自己动手写好了所有的内存管理代码。
说明:ARC只对可保留的对象指针(ROPs)有效。可保留的对象指针主要有以下三种:
(1) 代码块指针
(2)Objective-C对象指针
(3)通_attribute_((NSObject))类型定义的指针
使用ARC的三个条件
(1)能够确定哪些对象需要进行内存管理
(2)能够表明如何处理对象
(3)有可行的办法传递对象的所有权
第一个条件是对象的最上层集合知道如何去管理它的子对象。比方说你有一个通过malloc:方法创建的字符串数组:
NSString **myString;
myString = malloc(10* sizeof(NSString *));
这段代码创建了一个指向10个字符串的C型数组。因为C型数组不是可保留的对象,所以无法在这个结构体里使用ARC特性。
第二个条件是必须能够对某个对象保留计数器的值进行加1或减1的操作。也即是说所有NSObject类的子类都能进行内存管理。
第三个条件是在传递对象的时候,你的程序需要能够在调用者和接收者之间传递所有权。
2.4Weak(弱引用)
声明若引用的两种方式:声明变量时使用_weak关键字或对属性使用weak特性。
_weak NSString *myString;
@property(weak) NSString *myString;
使用ARC的时候有两种命名规则需要注意:
(1)、属性名称不能以new开头,比如说@property NSString *newString 是不允许的。
(2)、属性不能只有一个read-only而没有内训管理特性。如果你没有启用ARC,可以使用@property(readonly)NSString *title语句,但如果你启用了ARC功能,就必须制定由谁来管理内存。因为默认的特性是assign,所以进行一个简单的修复,使用unsafe_unretained就可以了。
3.异常
异常所有的关键字都是以@开头的。以下是它们的各自左右。
@try:定义用来检测的代码块以决定是否要抛出异常。
@catch():定义用来处理已抛出异常的代码块。接受一个参数,通常是NSExecption类型,但也可能是其他类型。
@finally:定义无论是否有抛出异常都会执行代码块,这段代码块总是执行的。
@throw:抛出异常。
3.1抛出异常
当程序检测到了异常,就必须向处理它的代码块报告这个异常。
程序会创建一个NSExecption实例来抛出异常,并会使用以下两种技术之一:
(1)使用“@”throw异常名";语句来抛出异常;
(2)向某个NSException对象发送raise消息。例如:
NSExecption *theException = [NSException exceptionWithName:...];
要抛出这个异常可以用这个语句
@throw theException;
或者用
[theException raise];
两种方法不能同时使用。两种方法的区别是raise只对NSException对象有效,而@throw也可以用在其他对象上。
3.2异常内存管理
如果代码中有异常,内存管理执行起来会比较复杂。例如:
- (void)mySimpleMethod
{
NSDictiongary *dictiongary = [[NSDictionary alloc] initWith..];
[self processDictiongary:dictionary];
[dictionary release];
}
现在假设processDictionary抛出了一个异常。程序从这个方法中跳出并寻找异常处理代码。由于现在方法已经退出来了,所以字典对象并没有被释放,于是就会出现内训泄露。
一种简单的解决办法就是使用@try 和@finally代码块,因为@finally总是会执行的。
- (void) mySimpleMethod
NSDictionary *dictionary = [[NSDictionary alloc] initWith...];
@try{
[self processDictionary:dictionary];
}
@finally{
[dictionary release];
}
- 7.内存管理
- 7. 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- 内存管理
- IOS-学习笔记(3)
- Linux内存buffer和cache的区别
- Activity声明周期解析
- Android Manifest.xml中intent-filter的(data)
- JQuery自动触发事件的方法
- 7. 内存管理
- C语言中exit(0)与exit(1)有什么区别
- Java设计模式学习---代理模式
- EJB系列(三)——EJB事务管理
- 集合初探(四)
- 使用js给input的value属性赋值
- PHPExcel数据导出
- HTML5 Canvas可拖动的弹性大树摇摆动画
- Excel数据处理:快速将数据依次放入大小不一的合并单元格