基础笔记
autorelease的基本用法
1> 会将对象放到一个自动释放池中
2> 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
3> 会返回对象本身
4> 调用完autorelease方法后,对象的计数器不变autorelease的好处
1> 不用再关心对象释放的时间
2> 不用再关心什么时候调用releaseautorelease的使用注意
1> 占用内存较大的对象不要随便使用autorelease
2> 占用内存较小的对象使用autorelease,没有太大影响
- 错误写法
1> alloc之后调用了autorelease,又调用release
@autoreleasepool
{
// 1
Person *p = [[[Person alloc] init] autorelease];
// 0
[p release];
}
2> 连续调用多次autorelease
@autoreleasepool
{
Person *p = [[[[Person alloc] init] autorelease] autorelease];
}
- 自动释放池
1> 在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
2> 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
- 自动释放池的创建方式
1> iOS 5.0前
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pool release]; // [pool drain];
2> iOS 5.0 开始
@autoreleasepool
{
}
- 系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的
8 .开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象
1> 创建对象时不要直接用类名,一般用self
+ (id)person
{
return [[[self alloc] init] autorelease];
}
// 调用的时候直接这样创建
Person *p = [Person person];
void test()
{
@autoreleasepool
{// { 开始代表创建了释放池
// autorelease方法会返回对象本身
// 调用完autorelease方法后,对象的计数器不变
// autorelease会将对象放到一个自动释放池中
// 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
Person *p = [[[Person alloc] init] autorelease];
p.age = 10;
}
进阶笔记
7.1 autorelease的具体使用方法
- 生成并持有NSAutoreleasePool对象
- 调用已分配对象的autorelease实例方法
- 销毁NSAutoreleasePool对象
7.2 NSAutoreleasePool对象生存周期相当于C语言的局部变量作用域,对所有调用过autorelease的实例方法的对象,在销毁NSAutoreleasePool对象是,都将调用release实例方法,即实例对象调用release方法
7.3 在cocoa框架中,主循环的Runloop会对NSAutoreleasePool进行生成持有或者销毁,因此程序员本身不一定非要使用NSAutoreleasePool进行开发
7.4 当对象调用了autorelease方法是实现实际大致可以理解为是调用的NSAutoreleasePool调用了类方法addObject
- (void) autorelease
{
[NSAutoreleasePool addObject: self];
}
NSAutoreleasePool调用addObject类方法的底层实现大致可以类比为
+ (void) addObject: (id) anObj
{
NSAutoreleasePool *pool = 取得正在使用的 NSAutoReleasePool对象;
if (pool != nil) {
[pool addObject: anObj];
} else {
NSLog(@"NSAutoreleasePool 对象为空状态下调用 autorelease方法");
}
}
NSAutoreleasePool的实例对象的 addObject(即上面代码中[pool addObject: anObj];
)的实际实现大致为
- (void) addObject: (id) anObj
{
[array addObject: anObj];
}
即类比为数组中添加已经调用过autorelease的对象
7.5 NSAutoreleasePool 调用drain方法对 NSAutoreleasePool进行销毁,其大致实现为
- (void) drain
{
[self delloc];
}
- (void) dealloc
{
[self emptyPool];
[array release];
}
- (void) emptyPool
{
for (id obj in array) {
[obj release];
}
}
主要目的是对数组中所有对象都调用release实例方法
7.6 showPool: 非公开的类方法,用于确认已被autorelease的对象的状况,其会将现在的 NSAutoreleasePool的状况打印到控制台上。在运行时系统中,非公开函数_objc_autoreleasePoolPrint()与此方法作用相同
RunLoop 相关
App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是_wrapRunLoopWithAutoreleasePoolHandler()
。
第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush()
创建自动释放池。其 order 是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。
第二个 Observer 监视了两个事件:
-
BeforeWaiting(准备进入休眠)
时调用_objc_autoreleasePoolPop()
和_objc_autoreleasePoolPush()
释放旧的池并创建新池; -
Exit(即将退出Loop)
时调用_objc_autoreleasePoolPop()
来释放自动释放池。
这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。
在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被 RunLoop 创建好的AutoreleasePool
环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了。