iOS autoreleasePool 深入理解

没有在网上找到好的关于autoreleasePool的文章,于是打算自己写一篇。从MRC中的自动引用计数开始写,便于理解ARC中的@autoreleasepool。文章地址 参考书籍:《Objective-C 高级编程》

MRC

autorelease是什么

autorelease会像C语言的自动变量那样来对待实例对象,在超出作用域的时候释放实例对象,不同的是autorelease可以来手动设定作用域的范围。

autorelease的使用

在MRC中我们通常在一下情况中使用autorelease

-(id)object{
	id = [[NSObject alloc] init];
    [obj aoturelease];   //这里没有使用NSAutoreleasePool,原因在下面会解释
    return obj;
}
复制代码

autorelease:取得对象的存在,但自己不持有对象。

autorelese提供这样的功能,使对象在超出指定的生存范围时能够自动并正确释放(调用release方法)。 autorelease将对象注册到autoreleasepool中,在pool结束(一般是作用域结束的时候),pool自动调用release

autorelease的具体使用过程:

  • 1、生成并持有NSAutoreleasePool对象;
  • 2、调用已分配对象的autoreleae实例方法;
  • 3、废弃NSAutoreleasePool对象。

示例代码:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  //区别于前面的代码这里使用了NSAutoreleasePool
id = obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];  //在调用这行代码时相当于调用了所有注册到pool中的对象的release方法。

复制代码

为什么有时候使用NSAutoreleasePool有时候不使用NSAutoreleasePool

原因:主循环的NSRunLoop会对NSAutoreleasePool进行生成和释放,所以开发者并不是一定得使用NSAutoreleasePool进行开发。也就是说就算你不生成NSAutoreleasePool,运行时也会自动生成一个。

什么时候使用NSAutoreleasePool对象

虽然NSRunloop会对生成的autorelease对象进行释放,但是短时间内生成的大量对象并不会立即释放,如下:

for(int i = 0 ; ;i++ ){
/**
* 读取图片
* 对图片进行处理
*/
}
//短时间内生成了大量的对象,并不会立即释放,这时候就会造成内存不足,从而引发卡顿。
复制代码

加入NSAutoreleasePool可以解决这个问题:

for(int i = 0 ; ;i++ ){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/**
* 读取图片
* 对图片进行处理
*/
[pool drain];//释放生成的局部变量,就不会造成对象的大量堆积
}
复制代码

autorelease的实现

[obj autorelease];
复制代码

我们来查看一下以上代码在GNUstep中的源代码

GNUstep是cocoa框架的互换框架。也就是说,GNUStep的源代码虽不能说与苹果的Cocoa实现完全相同,但是从使用者的角度来看,两者的行为和实现方式是一样的,或者说非常相似。理解了GNUstep源代码也就相当于理解了苹果的Cocoa实现。

-(id)autorelease
{
	[NSAutorelease addObject:self];
}
复制代码

autorelease实例方法的本质就是调用了NSAutoreleasePool对象的addObject类方法。 addObject方法的实现(源代码比较复杂,此为简化代码):

+(void)addObject:(id)object{
	NSAutoreleasePool *pool = 取得正在使用的NSAutoreleasePool对象;
    if(pool != nil){
    	[pool addObject:object];//pool存在一个array属性来添加所有注册到这个pool中的对象。
    }else{
    	//error
    }
}
复制代码

addObject方法中使用的pool对象正是你刚刚生成的NSAutoreleasePool对象,如果嵌套生成NSAutoreleasePool那么获取的pool就是你最内侧的pool对象,也就是“离你的对象最近的NSAutoreleasePool对象”。

[pool drain];这行代码在运行时会释放所有注册到pool中的对象。 我们来看下drain方法的实现。

-(void)drain
{
	[self dealloc];
}
-(void)dealloc
{
	[self emptyPool];
    [array release];
}
-(void)emptyPool
{
	for (id obj in array){
    	[obj release];
    }
}
复制代码

ARC中autoreleae的使用

ARC有效时我们无法使用autorelease方法,也不能使用NSAutoreleasePool类。但是我们会有书写更方便的替代方法。

使用姿势

ARC无效时:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id = obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain]; 
复制代码

ARC有效时:

@autoreleasepool{
	id obj = [[NSObject alloc] init];
}
复制代码

ARC有效时基本不会用到__autoreleasing修饰符,这里就不展开了,有疑问的同学可以留言

@autoreleasepool的实现

当你使用@autoreleasepool的时候,编译器会有一份替换代码。 你的代码:

@autoreleasepool{
	id obj = [[NSObject alloc] init];
}
复制代码

编译器的模拟代码:

id pool = objc_autoreleasePoolPush();
id = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(obj,@selector(init));
objc_autorelease(obj);
objc_autoreleasePoolPop(pool);
复制代码

我们可以看到编译器转换后的代码和我们前面的NSAutoreleasePool类的使用方式一模一样,所以不管ARC是否有效autorelease的功能一模一样。

转载于:https://juejin.im/post/5c90bbd0f265da60d36e6c39

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值