1.当我们创建一个对象时,(1)Person *p = [[Person alloc] init],就需要在下方执行一次(2)[p release],而[p release]一般放在最后,如果紧跟(1)的话,当创建完对象,对象就会被销毁,成为僵尸对象,假设,Person中有age属性,则再执行(3)p.age = 10;无疑会报错(野指针错误),如果放在程序的最后面的话,则p.age 正常执行。所以我们会担心(2)的乱放会造成许多错误。
例如:
解决方法是使用autorelease方法,其返回值是对象本身,autorelease会将对象放在一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作所以代码:(1)Person *p = [[Person alloc] init],(4) [p autorelease].
(1)(4)-> Person *p = [[[Person alloc] init]autorelease];
整体代码如下:
图示如下:
自动释放池销毁后:
注意:autorelease只是把对象扔到自动释放池里面(延迟了对象被销毁的时间),并不可以改变对象的计数器。改变计数器只有retain和release两种方法。缺点是:不能精确控制对象被销毁的时间,内存处理效率低(适用于占用内存比较小的对象,对象里面包含的属性主要是基本数据类型)。且autoreleasepool的存在是以栈结构存在的,栈结构的特点就是先进后出。当一个对象调用autorelease方法时,会将当前对象放到栈顶的释放池中。
autorelease和release不能同时适用。下面就是一个错误的使用:
autoreleasepool{
Car *c = [[[Car alloc] init] autorelease];
[c release];
}//野指针错误(message send to deallocted instance),当执行到这行代码时 c的计数器已经为0,但是释放池销毁,里面的对象需要再做一次release操作。(//或者 Car *c =[ [[[Car alloc] init] autorelease]autorelease];也是一个野指针错误)
2.ios 5.0版本以前:
自动是释放池的创建
NSAutoreleasePool*pool = [[NSAutoreleasePool alloc] init];
//对象代码区
[pool release];//销毁池子
或者[pool drain]//已经被淘汰
ios 5.0以后版本:
@autoreleasepool {
//
//
}
3.
1)Car *c = [[[Car alloc] init] autorelease];
如果要直接使用这句来创建对象的话,对于开发者,会觉得很浪费时间。所以如何优化这句代码呢?在开发过程中,我们会使用类方法,返回一个autorelease的对象。类方法返回对象类型(id)或(instancetype)。所以类方法如下:
+(instancetype)car{
return [[[Car alloc] init] autorelease];
}
创建对象时就可以
//返回一个调用autorelease方法的Car对象c
Car *c = [Carcar];
如果我们想要一个直接返回对速度赋初值的Car对象
则可以这样:
//这只是个类方法并不是构造方法
+(instancetype)car{
Car * c = [[[Caralloc] init] autorelease];
c.speed = 100;
return c ;
}
NSSting *str =@”1233”;
NSSting *str=[NSStringstringWithFormat:@”ha %d”,age ];
注意:系统自带方法里面如果没有包含alloc new 或者copy,说明返回的对象都是autorelease的。
规范:类方法的方法名一般以类名开头。类名相同的时候一般加前缀。
2)在开发过程中,如果父类有一个类方法可以快速创建一个调用autorelease方法的对象,在写类方法时,里面创建对象时我们要用self([[[self alloc] init] autorelease]),这样的话子类就不用重写这个方法来获取一个autorelease的对象。谁调用这个类方法,self则代表的就是谁。