自动引用技术
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实现
相关文章推荐
- Objective-C - ARC(Automatic Reference Counting)自动引用技术详解
- 自动引用技术ARC
- 黑马程序员——Objective-C程序设计(第4版)学习笔记之17-内存管理和自动引用计数——黑马 IOS 技术博客
- 自动引用技术ARC
- 自动引用技术ARC
- ARC自动引用技术
- Swift(十六、自动引用计数)
- OC学习篇之---数组对象的引用计数问题和自动释放池的概念
- C++ 引用计数技术及智能指针的简单实现及改进
- Swift-自动引用计数
- IOS开发技术之──头文件引用(@class/#import/#include)
- 非常经典的C++ 引用计数技术及智能指针的简单实现
- 以gmail为例,详细讲解C#技巧:网页表单自动填写技术
- iOS开发之ARC(自动引用计数)
- word添加引用及自动更新的方法
- 低调的苹果罕见发表论文,揭开自动驾驶汽车技术的冰山一角
- 黄聪:如何阻止iframe里引用的网页自动跳转
- Uber无人车发生全球首例行人致死事件,自动驾驶技术信度或倒退10年?
- IOS项目自动生成技术文档
- [MySql技术]mysql数据库自动备份