您的位置:首页 > 其它

自动引用技术

2015-09-21 15:21 183 查看

生成并持有对象-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实现
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: