该机能在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 可以使用该机能。简单地理解ARC,就是通过指定的语法,让编译器(LLVM 3.0)在编译代码时,自动生成实例的引用计数管理部分代码。有一点,ARC并不是GC,它只是一种代码静态分析(Static Analyzer)工具。

通过一小段代码,我们看看使用ARC前后的变化点。

  1. @interface NonARCObject : NSObject {
  2. NSString *name;
  3. }
  4. -(id)initWithName:(NSString *)name;
  5. @end
  6. @implementation NonARCObject
  7. -(id)initWithName:(NSString *)newName {
  8. self = [super init];
  9. if (self) {
  10. name = [newName retain];
  11. }
  12. return self;
  13. }
  14. -(void)dealloc {
  15. [name release];
  16. [Super dealloc];
  17. }
  18. @end
  1. @interface ARCObject : NSObject {
  2. NSString *name;
  3. }
  4. -(id)initWithName:(NSString *)name;
  5. @end
  6. @implementation ARCObject
  7. -(id)initWithName:(NSString *)newName {
  8. self = [super init];
  9. if (self) {
  10. name = newName;
  11. }
  12. return self;
  13. }
  14. @end
我们之前使用Objective-C中内存管理规则时,往往采用下面的准则
  • 生成对象时,使用autorelease
  • 对象代入时,先autorelease后再retain
  • 对象在函数中返回时,使用return [[object retain] autorelease];

而使用ARC后,我们可以不需要这样做了,甚至连最基础的release都不需要了。

使用ARC有什么好处呢?

  • 看到上面的例子,大家就知道了,以后写Objective-C的代码变得简单多了,因为我们不需要担心烦人的内存管理,担心内存泄露了
  • 代码的总量变少了,看上去清爽了不少,也节省了劳动力
  • 代码高速化,由于使用编译器管理引用计数,减少了低效代码的可能性
  • 记住一堆新的ARC规则 — 关键字及特性等需要一定的学习周期
  • 一些旧的代码,第三方代码使用的时候比较麻烦;修改代码需要工数,要么修改编译开关

关于第二点,由于 XCode4.2 中缺省ARC就是 ON 的状态,所以编译旧代码的时候往往有"Automatic Reference Counting Issue"的错误信息。

 

这个时候,可以将项目编译设置中的“Objectice-C Auto Reference Counteting”设为NO。如下所示。

 

如果只想对某个.m文件不适应ARC,可以只针对该类文件加上 -fno-objc-arc 编译FLAGS,如下图。

  • retain, release, autorelease, dealloc由编译器自动插入,不能在代码中调用
  • dealloc虽然可以被重载,但是不能调用[super dealloc]

由于ARC并不是GC,并需要一些规则让编译器支持代码插入,所以必须清楚清楚了这些规则后,才能写出健壮的代码。

ObjectiveC中的对象,有强参照(Strong reference)和弱参照(Weak reference)之分,当需要保持其他对象的时候,需要retain以确保对象引用计数加1。对象的持有者(owner)只要存在,那么该对象的强参照就一直存在。

对象处理的基本规则是

  • 只要对象的持有者存在(对象被强参照),那么就可以使用该对象
  • 对象失去了持有者后,即被破弃

强参照 (Strong reference)

 
(s1)

firstName作为”natsu”字符串对象的最初持有者,是该NSString类型对象的Strong reference。

(s2)

这里将firstName代入到aName中,即aName也成为了@”natsu”字符串对象的持有者,对于该对象,aName也是Strong reference。

(s3)

这里,改变firstName的内容。生成新的字符串对象”maki”。这时候firstName成为”maki”的持有者,而@”natsu”的持有者只有aName。每个字符串对象都有各自的持有者,所以它们都在内存中都存在。

(s4)

追加新的变量otherName, 它将成为@”maki”对象的另一个持有者。即NSString类型对象的Strong reference。

(s5)

将otherName代入到aName,这时,aName将成为@”maki”字符串对象的持有者。而对象@”natsu”已经没有持有者了,该对象将被破弃。

弱参照 (Weak reference)

接下来我们来看看弱参照 (Weak reference) 的使用方式。

(w1)

与强参照方式同样,firstName作为字符串对象@”natsu”的持有者存在。即是该NSString类型对象的Strong reference。

(w2)

使用关键字__weak,声明弱参照weakName变量,将firstName代入。这时weakName虽然参照@”natsu”,但仍是Weak reference。即weakName虽然能看到@”natsu”,但不是其持有者。

(w3)

firstName指向了新的对象@”maki”,成为其持有者,而对象@”natsu”因为没有了持有者,即被破弃。同时weakName变量将被自动代入nil。

ARC中关于对象的引用参照,主要有下面几关键字。使用strong, weak, autoreleasing限定的变量会被隐式初始化为nil。

  • __strong

变量声明缺省都带有__strong关键字,如果变量什么关键字都不写,那么缺省就是强参照。

  • __weak

上面已经看到了,这是弱参照的关键字。该概念是新特性,从 iOS 5/ Mac OS X 10.7 开始导入。由于该类型不影响对象的生命周期,所以如果对象之前就没有持有者,那么会出现刚创建就被破弃的问题,比如下面的代码。

  1. NSString __weak *string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
  2. NSLog(@"string: %@", string); //此时 string为空

如果编译设定OS版本 Deployment Target 设定为这比这低的版本,那么编译时将报错(The current deployment target does not support automated __weak references),这个时候,我们可以使用下面的 __unsafe_unretained。

弱参照还有一个特征,即当参数对象失去所有者之后,变量会被自动付上nil (Zeroing)。

  • __unsafe_unretained

该关键字与__weak一样,也是弱参照,与__weak的区别只是是否执行nil赋值(Zeroing)。但是这样,需要注意变量所指的对象已经被破弃了,地址还还存在,但内存中对象已经没有了。如果还是访问该对象,将引起「BAD_ACCESS」错误。

  • __autoreleasing

该关键字使对像延迟释放。比如你想传一个未初始化的对像引用到一个方法当中,在此方法中实例化此对像,那么这种情况可以使用__autoreleasing。他被经常用于函数有值参数返回时的处理,比如下面的例子。

  1. - (void) generateErrorInVariable:(__autoreleasing NSError **)paramError {
  2. ....
  3. *paramError = [[NSError alloc] initWithDomain:@"MyApp" code:1 userInfo:errorDictionary];
  4. }
  5. ....
  6. {
  7. NSError *error = nil;
  8. [self generateErrorInVariable:&error];
  9. NSLog(@"Error = %@", error);
  10. }

又如函数的返回值是在函数中申请的,那么希望释放是在调用端时,往往有下面的代码。

  1. -(NSString *)stringTest
  2. {
  3. NSString *retStr = [NSString stringWithString:@"test"];
  4. return [[retStr retain] autorelease];
  5. }
  6. // 使用ARC
  7. -(NSString *)stringTest
  8. {
  9. __autoreleasing NSString *retStr = [NSString alloc] initWithString:@"test"];
  10. return retStr;
  11. }

即当方法的参数是id*,且希望方法返回时对象被autoreleased,那么使用该关键字。

基本的ARC使用规则

  • 代码中不能使用retain, release, retain, autorelease
  • 不重载dealloc(如果是释放对象内存以外的处理,是可以重载该函数的,但是不能调用[super dealloc])
  • 不能使用NSAllocateObject, NSDeallocateObject
  • 不能在C结构体中使用对象指针
  • id与void *间的如果cast时需要用特定的方法(__bridge关键字)
  • 不能使用NSAutoReleasePool、而需要@autoreleasepool块
  • 不能使用“new”开始的属性名称 (如果使用会有下面的编译错误”Property’s synthesized getter follows Cocoa naming convention for returning ‘owned’ objects”)
--------------------------------------------------------------------华丽的分割线--------------------------------------------------------------------
 

ARC工作原理是在编译程序的时候由xCode将内存操作的代码(如:retain,release 和 autorelease)自动添加到需要的位置。

ARC 只能在iOS4 和iOS5上使用,weak refrences 只能在iOS5上使用,并且只能是工程在ARC管理内存的时候才能用。
老版本的工程是可以转换成使用ARC的工程,转换规则包括:

1.去掉所有的retain,release,autorelease

2.把NSAutoRelease替换成@autoreleasepool{}块

3.把assign的属性变为weak

使用ARC的一些强制规定

1.不能直接调用dealloc方法,不能调用retain,release,autorelease,reraubCount方法,包括@selector(retain)的方式也不行

2.截图租户事故宣布dealloc方法来管理一些资源,但不能用来释放实例变量,也不能在dealloc方法里面去掉[super dealloc]方法,在ARC下父类的dealloc同样由编译器来自动完成

3.Core Foundation类型的对象任然可以用CFRetain,CFRelease这些方法

4.不能在使用NSAllocateObject和NSDeallocateObject对象

5.不能在c结构体中使用对象指针,如果有类似功能可以创建一个Objective-c类来管理这些对象

6.在id和void *之间没有简便的转换方法,同样在Objective-c和core Foundation类型之间的转换都需要使用编译器制定的转换函数

7.不能再使用NSAutoreleasePool对象,ARC提供了@autoreleasepool块来代替它,这样更加有效率

8.不能使用内存存储区(不能再使用NSZone)

9.不能以new为开头给一个属性命名

10.声明outlet时一般应当使用weak,除了对StoryBoard 这样nib中间的顶层对象要用strong

11.weak 相当于老版本的assign,strong相当于retain

对工程中的单个文件制定不使用ARC的方法:在targets的build phases选项下Compile Sources下选择要不使用arc编译的文件,双击它,输入-fno-objc-arc即可

属性值 关键字 所有权
strong __strong
weak __weak
unsafe_unretained __unsafe_unretained
copy __strong
assign __unsafe_unretained
retain __strong

strong

该属性值对应 __strong 关键字,即该属性所声明的变量将成为对象的持有者。

weak

该属性对应 __weak 关键字,与 __weak 定义的变量一致,该属性所声明的变量将没有对象的所有权,并且当对象被破弃之后,对象将被自动赋值nil。

并且,delegate 和 Outlet 应该用 weak 属性来声明。同时,如上一回介绍的 iOS 5 之前的版本是没有 __weak 关键字的,所以 weak 属性是不能使用的。这种情况我们使用 unsafe_unretained。

unsafe_unretained

等效于__unsafe_unretaind关键字声明的变量;像上面说明的,iOS 5之前的系统用该属性代替 weak 来使用。

copy

与 strong 的区别是声明变量是拷贝对象的持有者。

assign

一般Scalar Varible用该属性声明,比如,int, BOOL。

retain

该属性与 strong 一致;只是可读性更强一些。

读写相关的属性 (readwrite, readonly)

读写相关的属性有 readwrite 和 readonly 两种,如果使用ARC之后,我么需要注意一下 readonly 属性的使用。

比如下面的变量声明。

  1. @property (nonatomic, readonly) NSString *name;

一般声明为 readonly 的变量按理说应该不需要持有所有权了,但是在ARC有效的情况下,将出现下面的错误信息 :

 “ARC forbids synthesizing a property of an Objective-C object with unspecified ownership or storage attribute

如果定义了ARC有效,那么必须要有所有者属性的定义;所以我们的代码改成这样,就OK了

  1. @property (nonatomic, strong, readonly) NSString *name;

不过有一点,Scalar Varible的变量缺省都有 assign 的属性定义,所以不需要给他们单独的明示声明了。

 
 

ARC小知识的更多相关文章

  1. 蓝牙Bluetooth技术小知识

    蓝牙Bluetooth技术以及广泛的应用于各种设备,并将继续在物联网IoT领域担任重要角色.下面搜集整理了一些关于蓝牙技术的小知识,以备参考. 蓝牙Bluetooth技术始创于1994年,其名字来源于 ...

  2. HTML+CSS中的一些小知识

    今天分享一些HTML.CSS的小知识,希望能够对大家有所帮助! 1.解决网页乱码的问题:最重要的是要保证各个环节的字符编码一致! (1)编辑器的编辑环境的字符集(默认字符集):Crtl+U 常见的编码 ...

  3. iOS APP开发的小知识(分享)

          亿合科技小编发现从2007年第一款智能手机横空出世,由此开启了人们的移动智能时代.我们从一开始对APP的陌生,到现在的爱不释手,可见APP开发的出现对我们的生活改变有多巨大.而iOS AP ...

  4. Unix系统小知识(转)

    Unix操作系统的小知识 2.VI添加行号/翻页/清屏 .在对话模式时(即输完Esc再输入: ),输入“:set number”可以将编辑的文本加上行号.跟玩俄罗斯方块一样方便的上下左右移动箭头的快捷 ...

  5. salesforce 零基础开发入门学习(十)IDE便捷小知识

    在这里介绍两个IDE的便捷开发的小知识. 一) 本地调试 由于salesforce代码只能提交以后才能调试,所以很多时候调试代码很麻烦.新版增加了一个特性:即可以在本地调试相关的代码或者查看相关代码运 ...

  6. Jquery:小知识;

    Jquery:小知识: jQuery学习笔记(二):this相关问题及选择器   上一节的遗留问题,关于this的相关问题,先来解决一下. this的相关问题 this指代的是什么 这个应该是比较好理 ...

  7. HTML小知识---Label

    今天知道了一个html小知识: <input type="checkbox" id="chkVersion" />                 ...

  8. Unicode和汉字编码小知识

    Unicode和汉字编码小知识 将汉字进行UNICODE编码,如:“王”编码后就成了“\王”,UNICODE字符以\u开始,后面有4个数字或者字母,所有字符都是16进制的数字,每两位表示的256以内的 ...

  9. Java异常的一个小知识

    有以下两个代码: package com.lk.A; public class Test3 { public static void main(String[] args) { try { int a ...

随机推荐

  1. php与mysql的链接到底用mysql 还是mysqli,pdo

    参考:http://php.net/manual/en/mysqlinfo.api.choosing.php

  2. linux学习资料

    鸟哥的Linux私房菜 基础学习篇(第三版)    http://book.51cto.com/art/201007/211888.htm 鸟哥的Linux私房菜——服务器架设篇    http:// ...

  3. Windows 之 win10快捷键

    1.Windows10系统常用快捷键: 1)贴靠窗口(窗口可以变为1/4大小放置在屏幕4个角落):Win +左/右 或 Win +上/下 2)切换窗口:Alt + Tab 3)任务视图(松开键盘界面不 ...

  4. Python练习题 028:求3*3矩阵对角线数字之和

    [Python练习题 028] 求一个3*3矩阵对角线元素之和 ----------------------------------------------------- 这题解倒是解出来了,但总觉得 ...

  5. linux记录登录ip方法

    PS:Linux用户操作记录一般通过命令history来查看历史记录,但是如果因为某人误操作了删除了重要的数据,这种情况下history命令就不会有什么作用了.以下方法可以实现通过记录登陆IP地址和所 ...

  6. iOS UIwebView html 字符串转换

    解析json字段是一段html串,平常解析出来都能在uiwebview上正常显示,这却出现以下状况,文本内容夹杂好多不需要显示的字符,例如: NSString*string =@"<s ...

  7. u163是什么故障 佳能MX328 u163是什么意思?墨水打完了,我加了墨水后还是显示U163(请检查墨水-彩色)警告灯亮

    U163:墨水已用完.请更换墨盒,然后关闭“扫描单元”(“机盖”).如果打印正在进行并希望继续打印,请在不取出墨盒的情况下按 [Stop] (停止) 按钮至少 5 秒. 然后可以在墨水用完的情况下继续 ...

  8. Oracle基础 PL-SQL编程基础(1) 变量和常量

    一.什么是PL-SQL PL-SQL是结合了Oracle过程语言和结构化查询语言(SQL)的一种扩展语言.具体来说,PL-SQL就是在普通的SQL语句的基础上增加了编程语言的特点,将数据操作和查询语句 ...

  9. mysql表的创建和删除

    在创建数据库表时,最好是在编辑器中写好创建表的代码,然后粘贴到命令行中,这样如果有错修改起来方便. 现在来创建一个user表: -- 打开数据库, --后面必须要有空格, 表示注释 USE mydb3 ...

  10. 在项目中使用SQLite数据库小结

    ------------------------------------------------------------------------推荐: - VS2012 使用 1.0.84 版的库 - ...