还是要好好学习英文啊,笔者只能看中文版的,下载地址如下:
http://download.csdn.net/detail/m6830098/7977521
看书的时候还是困的不行不行的-
今天来学习学习本书的第五章。
第一条:理解引用计数。引用计数工作原理,在引用计数架构下,对象有个计数器,用以表示当前有多少个事物想令此对象继续存在。NSObject协议中有三个方法用于操作计数器,以递增或递减其值:Retain 递增保留计数;release 递减保留计数; autorelease 待稍后清理"自动释放池(autorelease pool)"时,在递减保留计数。为了避免在不经意间使用了无效对象,一般调用完release之后都会清空指针。这就能保证不会出现可能指向无效对象的指针,这种情况通常称为"悬挂指针"(dangling pointer)。保留环:使用引用计数机制时,经常要注意的一个问题就是"保留环(retain cycle)",也就是呈现环状互相引用的对个对象,这将导致内存泄漏,因为循环中的对象其保留计数不会降为0.
第二条:以ARC简化引用计数。由系统自动执行retain、release、autorelease、dealloc操作。若方法名以下列词语开头,则其返回的对象归调用者所有:copy、new、alloc、mutableCopy。归调用者所有的意思是:调用上述四种方法的那段代码要负责释放方法所返回的对象。可用下列修饰符改变局部变量与实例变量的语义:1.
_ strong:默认语义,保留此值。2. unsafe unretained:不保留此值,这么做可能不安全,因为等到再次使用变量时,其对象可能已近回收了。3. _weak:不保留此值,但是变量可以安全使用,因为如果系统把这个对象回收了,那边变量也会自动清空。4.
_ _autoreleasing:把对象"按引用传递"(pass by reference)给方法时,使用这个特殊的修饰符。此值在方法返回时自动释放。在ARC环境下,dealloc方法可以像这样写:
- (void)dealloc {
CFRelease(_coreFoundationObject);
free(_heapAllocatedMemoryBlob);
}
注意:ARC只负责管理Object-C对象的内存。CoreFoundation对象不归ARC管理(因为他们是由纯C的API所生成的),开发者必须适时调用CFRetain/CFRelease。
第三条:在dealloc方法中只释放引用并解除监听。对象在经历其生命周期后,最终会为系统所回收,这时就要执行dealloc方法了。在每个对象的生命期内,此方法仅执行一次,也就是当保留计数降为0的时候。在dealloc方法中,通常还要做一件事,那就是把原来配置过的观测行为都清理掉。如果用NSNotificationCenter给此对象订阅(register)过某种通知,那么一般应该在这里注销,通知系统就不在把通知发给回收后的对象了,若还是向其发送通知,这会让应用程序崩溃。
- (void)dealloc {
CFRelease(_coreFoundationObject);
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
第四条:以弱引用来避免保留环。避免保留环的最佳方式就是弱引用。
第五条:以"自动释放池块"降低内存峰值。释放对象有两种方式:一种是调用release方法,使其保留计数立即递减;另一种是调用autorelease方法,将其加入"自动释放池"中。自动释放池用于存放那些需要在稍后某个时刻释放的对象。清空(drain)自动释放池时,系统会向其中的对象发送release消息。创建自动释放池的语法:
@autoreleasepool {
//...
}
一般情况下无须担心自动释放池的创建问题,系统会自动创建一些线程,比如主线程或者"大中枢派发(Grand Central Disoatch,GCD)"机制中的线程,这些线程某人都有自动释放池,每次执行"事件循环(enent loop)"时,就会将其清空。当循环长度无法预知,必须取决于用户的输入时,如果不使用"自动释放池块",应用程序所占内存量就会持续上涨,而等到下一个事件时,所有临时对象都释放后内存量又会突然下降,这种情况不甚理想。如:要从数据库中读出许多对象,代码可能这么写:
NSArray *dataBaseRecords= /* ... */;
NSMutableArray *people = [NSMutableArray new];
for (NSDictionary *record in dataBaseRecords) {
WWPerson *person = [WWPerson alloc] initWithRecord:record];
[people addObject:person];
}
这个就会创建一些临时对象,若记录有很多条,则内存中也会有很多不必要的临时对象,它们本来应该是提早回收的。增加一个自动释放池既可解决问题。如果把循环内的代码包裹在"自动释放池块"中,那么在循环中自动释放的对象就会放在这个池,而不是主线程的主池里面。如:
NSArray *dataBaseRecords= /* ... */;
NSMutableArray *people = [NSMutableArray new];
for (NSDictionary *record in dataBaseRecords) {
@autoreleasepool {
WWPerson *person = [[WWPerson alloc] initWithRecord:record];
[people addObject:person];
}
}
自动释放池机制就像"栈(stack)"一样,系统创建好自动释放池之后就将其推入栈中,二清空自动释放池,曾相当于将其从栈中弹出。在对象上执行自动释放操作,就不等于将其方圆栈顶的那个池里。@autoreleasepool语法还有个好处:每个自动释放池均有其范围,可以避免我已经误用了那些在清空池后已为系统所回收的对象。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id object = [self createObject];
[pool drain];
[self useObject:object];
最后,本书一共7个章节,此为第五章节:内存管理。由于现在都使用ARC机制,所以本章有一些内容我没有列举下来。
共勉!一步一个巴掌印。。。。。
网友评论