自动引用技术

生成并持有对象-alloc,new,copy,mutableCopy等方法

持有对象-retain方法

释放对象-release方法

废弃对象-dealloc方法


自己生成的对象,自己持有

使用alloc、new、copy、mutableCopy名称开头的方法名意味着自己生成的对象只有自己持有。

使用NSObject类的alloc类方法,new类方法能自己生成并持有对象。

allocMyObject、newThatObject、copyThis、mutableCopyYourObject这样的方法,也意味着自己生成并持有对象。

id obj = [NSObject new];
id obj = [[NSObject alloc] init];

非自己生成的对象,自己也能持有

因为非自己生成并持有,所以自己不是该对象的持有者。使用retain方法,使非自己生成的对象跟用alloc、new、copy、mutableCopy方法生成并持有的对象一样,成为了自己所持有的。

id obj = [NSMutableArray array];
//取得的对象存在,但自己不持有对象。
[obj retain];

不再需要自己持有的对象时释放

自己持有的对象,一旦不再需要,持有者有义务释放该对象。释放使用release方法。用alloc方法由自己生成并持有的对象就通过release方法释放了。使用retain方法持有的对象,也同样可以用release方法释放。

id obj = [NSObject new];
[obj release];

id obj = [NSMutableArray array];
[obj retain];
[obj release];<pre name="code" class="objc">-(id) allocObject
{
	id obj = [NSObject new];
	return obj;
}
id obj1 = [obj0 allocObject];
//自己生成持有对象 allocObject

-(id) object
{
	id obj = [NSObject new];
	[obj autorelease];
	//取得的对象存在,但自己不持有对象
	return obj;
}
id obj1 = [obj0 object];
//取得的对象存在,但自己不吃油对象
[obj1 retain];
//自己持有对象
</pre>

autorelease方法,可以使取得的对象存在,但自己不持有对象。autorelease提供这样的功能,使对象在超出制定的生存范围时能够自动并正确地释放(调用release方法)。


无法释放非自己持有的对象
对于用alloc、new、copy、mutableCopy方法生成并持有的对象,或是使用retain方法持有的对象,由于持有者是自己,所有在不需要该对象时需要将其释放。而由此以外所得到的对象绝对不能释放。倘若在应用程序中释放了非自己所持有的对象就会造成崩溃。例如自己生成并持有对象后,在释放完不再需要的对象之后再次释放。
id obj = [NSObject new];
//自己持有对象
[obj release];
//对象已释放
[obj release];
//释放之后再次释放已非自己持有的对象。应用程序崩溃。
//崩溃情况:再度废弃已经废弃了的对象时崩溃,访问已经废弃的对象时崩溃。

id obj1 = [obj0 object];
[obj release];

alloc、retain、release、dealloc实现
通过allocWithZone:类方法调用NSAllocateObject函数分配了对象.NSAllocateObject函数通过调用NSZoneMalloc函数来分配存放对象所需要的内存空间,之后将该内存个空间置0,最后反悔作为对象而使用的指针。
struct obj_layout {
	NSUinteger retained;
};
inline id
NSAllocateObject(Class aClass,NSUInteger extraBytes,NSZone *zone)
{
	int size = 计算容纳对象所需内存大小;
	id new = NSZoneMalloc(zone,size);
	memset(new,0,size);
	new = (id) & ((struct obj_layout *)new)[1];
}
NSZone,防止内存碎片化而引入的结构。对内存分配的区域本身进行多重化管理,根据使用对象的目的、对象的大小分配内存,从而提高了内存管理的效率。
p14
去掉NSZone后简化了的源代码:
struct obj_layout {
	NSUInteger retained;
};
+(id) alloc
{
	int size = sizeof(struct obj_layout) + 对象大小;
	struct obj_layout *p = (struct obj_layout *) calloc (1,size);
	return (id)(p+1);
}
alloc类方法用struct obj_layout中的retained整数来保存引用计数,并将其写入对象内存头部,该对象内存块全部置0后返回。
对象的引用计数可以通过retainCount实例方法取得
id obj = [NSObject new];
NSLog(@"retainCount = %d",[obj retainCount]);
在OC的对象中存有引用计数这一整数值。
调用alloc或是retain方法后,引用计数值加1。
调用release后,引用计数减1。
引用计数值为0时,调用dealloc方法废弃对象。

autorelease
autorelease会像C语言的自动变量那样来对待对象实例。当超出其作用域(相当于变量作用域)时,对象实例的release实例方法被调用。另外,同C语言的自动变量不同的是,编程人员可以设置变量的作用域。
autorelease的具体使用方法:
(1)生成并持有NSAutoreleasePool对象;
(2)调用已分配对象的autorelease实例方法;
(3)废弃NSAutoreleasePool对象。
NSAutoreleasePool *pool = [NSAutoreleasePool new];
id obj = [NSObject new];
[obj autorelease];
[pool drain];
在大量产生autorelease的对象时,只要不废弃NSAutoreleasePool对象,那么生成的对象就不能被释放,因此有时会产生内存不足的现象。
典型的例子是读入大量图像的同时改变其尺寸。图像文件读入到NSData对象,并从中生成UIImage对象,改变该对象尺寸后生成新的UIImage对象。这种情况下,就会大量产生autorelease的对象。但是不会自动废弃NSAutoreleasePool对象。有必要在适当的地方生成、持有或废弃NSAutoreleasePool对象。
for (int i = 0;i < 图像数; i++ )
{
	NSAutoreleasePool *pool = [NSAutoreleasePool new];
	//读入图像,大量产生autorelease的对象
	[pool drain];
	//通过drain,autorelease的对象被一起release。
}
ARC规则

所有权修饰符
_strong修饰符
是id类型和对象类型默认的所有权修饰符。
附有_strong修饰符的变量obj在超出其变量作用域时,即在该变量被废弃时,会释放其被赋予的对象。
如“strong”这个名称所示,_strong修饰符表示对对象的“强引用”。持有强引用的变量在超出其作用域时被废弃,随着强引用的失效,引用的对象会随之释放。
{
	id _strong obj = [NSObject new];
	//因为变量obj为强引用,自己持有对象
	
	id _strong obj1 = [NSMutableArray array];
	//因为变量obj1为强引用,自己持有对象
}
//因为变量obj超出其作用域,强引用失效,所以自动地释放自己持有的对象。对象的所有者不存在,因此废弃该对象。
//因为变量obj1超出其作用域,强引用失效,所以自动地释放自己持有的对象。对象的所有者不存在,因此废弃该对象。
	附有_strong修饰符的变量之间可以相互赋值:
id _strong obj0 = [NSObject new]; //对象A
//obj0 持有对象A的强引用
id _strong obj1 = [NSObject new]; //对象B
//obj0 持有对象B的强引用
id _strong obj2 = nil;
//obj2不持有任何对象
obj0 = obj1;
//obj0持有由obj1赋予的对象B的强引用,所以原先持有的对对象A的强引用失效。对象A的所有者不存在,因此废弃对象A。
obj2 = obj0;
//obj2持有由obj0赋予的对象B的强引用。
obj1 = nil;
obj0 = nil;
obj2 = nil;
//对对象B的强引用失效,对象B的所有者不存在,因此废弃对象B。

_weak修饰符
循环引用容易发生内存泄漏。所谓的内存泄漏就是应当废弃的对象在超出其生存周期后继续存在。
弱引用不能持有对象实例。
{
	//自己生成并持有对象
	id _strong = obj0 = [NSObject new];
	//因为obj0变量为强引用,所以自己持有对象
	
	id _weak obj1 = obj0;
	//obj1变量持有生成对象的弱引用
}
	//因为obj0变量超出其作用域,强引用失效。所以自动释放自己持有的对象。因为对象的所有者不存在,所以废弃该对象。
	因为带_weak修饰符的变量(即弱引用)不持有对象,所以在超出其变量作用域时,对象即被释放。
	_weak修饰符,在持有某对象的弱引用时,若该对象被废弃,则此弱引用将自动失效且处于nil被赋值的状态(空弱引用)。

id _weak obj1 = nil;
{
	id _strong obj0 = [NSObject new];
	obj1 = obj0;
	//obj1变量持有对象的弱引用
	NSLog(@"A:%@",obj1);
}
//obj0变量超出作用域,强引用失效,自动释放自己持有的对象。因为对象无持有者,所以废弃该对象。所以obj1变量的弱引用实现,nil赋值给obj1.
NSLog(@"B:%@",obj1);
//输出:
A:<NSObject:0x753e180>
B:(null)

_unsafe_unretained修饰符
不安全的所有权修饰符。尽管ARC式的内存管理是编译器的工作,但附有_unsafe_unretaind修饰符的变量不属于编译器的内存管理对象。
同_weak修饰符的变量一样,因为自己生成并持有的对象不能继续为自己所有,所以生成的对象会被立即释放。
赋值给附有_unsafe_unretained修饰符变量的对象在通过该变量使用时,如果没有确保其确实存在,那么应用程序就会崩溃。

_autoreleasing修饰符
ARC有效时,制定@autoreleasepool块来代替NSAutoreleasePool类对象生成、持有以及废弃。ARC有效时,要通过将对象赋值给附加了_autoreleasing修饰符的变量来替代调用autorelease方法。对象赋值给附有_autoreleasing修饰符的变量等价于在ARC无效时调用对象的autorelease方法,即对象被注册到autoreleasepool。
编译器会检查方法名是否以alloc、new、copy、mutableCopy开始,如果不是则自动将返回值的对象注册到autoreleasepool。
init方法返回值的对象不注册到autoreleasepool。
+(id) array
{
id obj = [ [NSMutableArray alloc] init];
return obj;
}
因为没有显示指定所有权修饰符,所以obj是强引用。由于return使得对象变量超出其作用域,所以该强引用对应的自己持有的对象会被自动释放, 但该对象作为函数的返回值,编译器会自动将其注册到autoreleasepool。
id _weak obj1 = obj0;
id _autoreleasing tmp = obj1;
NSLog(@"class = %@",[tmp class]);
_weak修饰符只持有对象的弱引用,而在访问引用对象的过程中,该对象可能被废弃。如果把要访问的对象注册到autoreleasepool中,那么在autoreleasepool块结束之前都能确保该对象存在。因此,在使用附有_weak修饰符的变量时就必定要使用注册到autoreleasepool中的对象。

id的指针或者对象的指针在没有显示指定时会被附加上_autoreleasing修饰符。
赋值给对象指针时,所有权修饰符必须一致
NSError *error = nil;
NSError * _strong *pError = &error;

-(BOOL) performOperationWithErroe:(NSError * _autoreleasing *)error;
NSError _strong *error = nil;
BOOL result = [obj performOperationWithError:&error];
	//编译器自动的将该源代码转化成了下面形式
NSError _strong *error = nil;
NSError _autoreleasing *tmp = error;
BOOL result = [obj performOperationWithError: &tmp];
error =tmp;
为了在使用参数取得对象时,要将参数声明为附有_autoreleasing修饰符的对象指针类型。虽然可以非显式地指定_autoreleasing修饰符,但在显式的指定时,必须注意对象变量要为自动变量(包括局部变量、函数以及方法参数)。

在ARC有效时的规则
不能使用retain、release、retainCount、autorelease
不能使用NSAllocateObject、NSDeallocateObject
须遵守内存管理的方法命名规则
不要显式的调用dealloc
使用@autoreleasepool块替代NSAutoreleasePool
不能使用区域NSZone
对象型变量不能作为C语言结构体(struct、union)的成员
显式转换”id“和”void *“

init
以init开始的方法,必须是实例方法,并且必须要返回对象。返回的对象应为id类型或该方法声明类的对象类型,抑或是该类的超类型或子类型。该返回对象并不注册到autoreleasepool上。基本上只是对alloc方法返回值的对象进行初始化并返回该对象。
属性

id _weak obj;
@property (nonatomic,weak) id  obj;

数组
_unsafe_unretained修饰符以外的_strong、_weak、_autoreleasing修饰符保证其指定的变量初始化为nil。同样,附有_strong、_weak、_autoreleasing修饰符变量的数组也保证其初始化为nil。

ARC实现
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值