weak的实现原理是什么 ios

 我来答
匿名用户
2017-03-25
展开全部
ARC的本质 ARC是编译器(时)特性,而不是运行时特性,更不是垃圾回收器(GC)。 Automatic Reference Counting (ARC) is a compiler-level feature that simplifies the process of managing object lifetimes (memory management) in Cocoa applications. ARC只是相对于MRC(Manual Reference Counting或称为非ARC,下文中我们会一直使用MRC来指代非ARC的管理方式)的一次改进,但它和之前的技术本质上没有区别。具体信息可以参考ARC编译器官方文档。 ARC的开启与关闭 不同于XCode4可以在创建工程时选择关闭ARC,XCode5在创建的工程是默认开启ARC,没有可以关闭ARC的选项。 如果需要对特定文件开启或关闭ARC,可以在工程选项中选择Targets -> Compile Phases -> Compile Sources,在里面找到对应文件,添加flag: 打开ARC:-fobjc-arc 关闭ARC:-fno-objc-arc 如图: ARC的修饰符 ARC主要提供了4种修饰符,他们分别是:__strong,__weak,__autoreleasing,__unsafe_unretained。 __strong 表示引用为强引用。对应在定义property时的"strong"。所有对象只有当没有任何一个强引用指向时,才会被释放。 注意:如果在声明引用时不加修饰符,那么引用将默认是强引用。当需要释放强引用指向的对象时,需要将强引用置nil。 __weak 表示引用为弱引用。对应在定义property时用的"weak"。弱引用不会影响对象的释放,即只要对象没有任何强引用指向,即使有100个弱引用对象指向也没用,该对象依然会被释放。不过好在,对象在被释放的同时,指向它的弱引用会自动被置nil,这个技术叫zeroing weak pointer。这样有效得防止无效指针、野指针的产生。__weak一般用在delegate关系中防止循环引用或者用来修饰指向由Interface Builder编辑与生成的UI控件。 __autoreleasing 表示在autorelease pool中自动释放对象的引用,和MRC时代autorelease的用法相同。定义property时不能使用这个修饰符,任何一个对象的property都不应该是autorelease型的。 一个常见的误解是,在ARC中没有autorelease,因为这样一个“自动释放”看起来好像有点多余。这个误解可能源自于将ARC的“自动”和autorelease“自动”的混淆。其实你只要看一下每个iOS App的main.m文件就能知道,autorelease不仅好好的存在着,并且变得更fashion了:不需要再手工被创建,也不需要再显式得调用[drain]方法释放内存池。 以下两行代码的意义是相同的。 NSString *str = [[[NSString alloc] initWithFormat:@"hehe"] autorelease]; // MRC NSString *__autoreleasing str = [[NSString alloc] initWithFormat:@"hehe"]; // ARC 这里关于autoreleasepool就不做了,详细地信息可以参考官方文档或者其他文章。 __autoreleasing在ARC中主要用在参数传递返回值(out-parameters)和引用传递参数(pass-by-reference)的情况下。 __autoreleasing is used to denote arguments that are passed by reference (id *) and are autoreleased on return. 比如常用的NSError的使用: NSError *__autoreleasing error; if (![data writeToFile:filename options:NSDataWritingAtomic error:&error]) {   NSLog(@"Error: %@", error); } (在上面的writeToFile方法中error参数的类型为(NSError *__autoreleasing *)) 注意,如果你的error定义为了strong型,那么,编译器会帮你隐式地做如下事情,保证最终传入函数的参数依然是个__autoreleasing类型的引用。 NSError *error; NSError *__autoreleasing tempError = error; // 编译器添加 if (![data writeToFile:filename options:NSDataWritingAtomic error:&tempError]) {   error = tempError; // 编译器添加   NSLog(@"Error: %@", error); } 所以为了提高效率,避免这种情况,我们一般在定义error的时候将其(老老实实地=。=)声明为__autoreleasing类型的: NSError *__autoreleasing error; 在这里,加上__autoreleasing之后,相当于在MRC中对返回值error做了如下事情: *error = [[[NSError alloc] init] autorelease]; *error指向的对象在创建出来后,被放入到了autoreleasing pool中,等待使用结束后的自动释放,函数外error的使用者并不需要关心*error指向对象的释放。 另外一点,在ARC中,所有这种指针的指针 (NSError **)的函数参数如果不加修饰符,编译器会默认将他们认定为__autoreleasing类型。 比如下面的两段代码是等同的: - (NSString *)doSomething:(NSNumber **)value { // do something } - (NSString *)doSomething:(NSNumber * __autoreleasing *)value { // do something } 除非你显式得给value声明了__strong,否则value默认就是__autoreleasing的。 最后一点,某些类的方法会隐式地使用自己的autorelease pool,在这种时候使用__autoreleasing类型要特别小心。 比如NSDictionary的[enumerateKeysAndObjectsUsingBlock]方法: - (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error { [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){ // do stuff if (there is some error && error != nil) { *error = [NSError errorWithDomain:@"MyError" code:1 userInfo:nil]; }  }]; } 会隐式地创建一个autorelease pool,上面代码实际类似于: - (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error { [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){ @autoreleasepool // 被隐式创建       { if (there is some error && error != nil) { *error = [NSError errorWithDomain:@"MyError" code:1 userInfo:nil]; }  } }]; // *error 在这里已经被dict的做枚举遍历时创建的autorelease pool释放掉了 :( } 为了能够正常的使用*error,我们需要一个strong型的临时引用,在dict的枚举Block中是用这个临时引用,保证引用指向的对象不会在出了dict的枚举Block后被释放,正确的方式如下: - (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error {   __block NSError* tempError; // 加__block保证可以在Block内被修改   [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop)   {     if (there is some error)     {       *tempError = [NSError errorWithDomain:@"MyError" code:1 userInfo:nil];     }    }]   if (error != nil)   {     *error = tempError;   }  }
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式