ARC是什么

ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting)。简单地说,就是代码中自动加入了retain/release,原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。

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

变化点

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

 @interface NonARCObject : NSObject {
NSString *name;
}
-(id)initWithName:(NSString *)name;
@end @implementation NonARCObject
-(id)initWithName:(NSString *)newName {
self = [super init];
if (self) {
name = [newName retain];
}
return self;
} -(void)dealloc {
[name release];
[Super dealloc];
}
@end
 @interface ARCObject : NSObject {
NSString *name;
}
-(id)initWithName:(NSString *)name;
@end @implementation ARCObject
-(id)initWithName:(NSString *)newName {
self = [super init];
if (self) {
name = newName;
}
return self;
}
@end
我们之前使用Objective-C中内存管理规则时,往往采用下面的准则
  • 生成对象时,使用autorelease
  • 对象代入时,先autorelease后再retain
  • 对象在函数中返回时,使用return [[object retain] autorelease];

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

使用ARC的好处

使用ARC有什么好处呢?

  • 看到上面的例子,大家就知道了,以后写Objective-C的代码变得简单多了,因为我们不需要担心烦人的内存管理,担心内存泄露了
  • 代码的总量变少了,看上去清爽了不少,也节省了劳动力
  • 代码高速化,由于使用编译器管理引用计数,减少了低效代码的可能性

不好的地方

  • 记住一堆新的ARC规则 — 关键字及特性等需要一定的学习周期
  • 一些旧的代码,第三方代码使用的时候比较麻烦;修改代码需要工数,要么修改编译开关

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

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

 

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

ARC基本规则

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

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

Objective-C对象

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 开始导入。由于该类型不影响对象的生命周期,所以如果对象之前就没有持有者,那么会出现刚创建就被破弃的问题,比如下面的代码。

 NSString __weak *string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
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。他被经常用于函数有值参数返回时的处理,比如下面的例子。

 - (void) generateErrorInVariable:(__autoreleasing NSError **)paramError {
....
*paramError = [[NSError alloc] initWithDomain:@"MyApp" code: userInfo:errorDictionary];
} ....
{
NSError *error = nil;
[self generateErrorInVariable:&error];
NSLog(@"Error = %@", error);
}

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

 -(NSString *)stringTest
{
NSString *retStr = [NSString stringWithString:@"test"]; return [[retStr retain] autorelease];
} // 使用ARC -(NSString *)stringTest
{
__autoreleasing NSString *retStr = [NSString alloc] initWithString:@"test"]; return retStr;

即当方法的参数是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的更多相关文章

  1. Convert BSpline Curve to Arc Spline in OpenCASCADE

    Convert BSpline Curve to Arc Spline in OpenCASCADE eryar@163.com Abstract. The paper based on OpenCA ...

  2. 黑马程序员——ARC机制总结和用ARC建立模型

    ARC 全称:Automatic Reference Counting 使用ARC 只需要在建立一个新的项目的时候把 下面的√打上 Xcode5以后都会默认建议开发者使用ARC机制 新的项目中如果有部 ...

  3. JSONKit在项目中使用设置(ARC与方法更新)

    在项目中经常会遇到解析json的情况,如果有同学想要解析JSON,那么JSONKit可以是一个不错的选择. git中JSONKit 的地址为:https://github.com/johnezang/ ...

  4. MRC迁移ARC之__block

    今日帮着同事把老项目从MRC迁移至ARC,大部分工作无非是删除release,[super dealloc]等方法,只要关闭了MRC编译选项后,编译器能自动帮你检查,block就有一些不一样了,发现许 ...

  5. Arc GIS engine10.2与VS2012的安装及匹配步骤

      本文章已收录于:   .embody { padding: 10px 10px 10px; margin: 0 -20px; border-bottom: solid 1px #ededed } ...

  6. 关于ARC下需要dealloc的相关内容

    今天在项目中使用KVO添加观察者模式的时候,在返回上一级的时候竟然崩了.可是,看了很久,代码没有问题.最后,终于知道了需要添加dealloc 防止以后再出错,所以,便纪录下来.关于ARC下需要手动释放 ...

  7. iOS 中 ARC 项目 兼容 MRC

    iOS 项目中MRC 和 ARC 项目的代码兼容问题: 1.ARC 项目中导入 MRC 第三方类的时候要在此类上添加 -objc-arc. 2.MRC 项目中导入 ARC 类的时候要在次类上添加 -f ...

  8. ARC内存管理机制详解

    ARC在OC里面个人感觉又是一个高大上的牛词,在前面Objective-C中的内存管理部分提到了ARC内存管理机制,ARC是Automatic Reference Counting---自动引用计数. ...

  9. objective-c 语法快速过(7)编译器特性ARC

    ARC(是编译器特性) ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的retain.release.autorelease语句.你不再需要担心内 ...

  10. iOS通过ARC管理内存(内容根据iOS编程编写)

    栈 当程序执行某个方法(或函数)时,会从内存中一个叫栈的区域分配一块内存空间,这块内存空间我们叫帧.帧负责保护程序在方法内声明的变量的值.在方法内声明的变量我们称之为局部变量. 当我们的程序开始启动, ...

随机推荐

  1. centos6.5 下搭建lamp环境

    一直以为很麻烦,实际操作起来并没有遇到什么问题,yum源是163,php版本是5.3(有点老,以后再更新吧):详细步骤如下: 第一步:安装php mysql apache yum -y install ...

  2. Atom支持Markdown和Latex

    本篇博客主要用于记录Atom编辑器同时支持markdown和latex: 1.安装 安装方法1: (Windows系统)File->Settings->Install中搜索markdown ...

  3. bootstrap走动的进度条

    1.页面效果: 起始位置:

  4. 控制对话框风格的activity的显示大小与位置

    项目开发的需要,因为到现在项目接近完工,用户提出对条件筛选方式进行修改,为做到最小的改动实现用户的需求,各种百度,对于对话框风格大家普遍使用PopupWindow,但由于之前开发设计时使用的是acti ...

  5. 应用程序框架实战十三:DDD分层架构之我见

    前面介绍了应用程序框架的一个重要组成部分——公共操作类,并提供了一个数据类型转换公共操作类作为示例进行演示.下面准备介绍应用程序框架的另一个重要组成部分,即体系架构支持.你不一定要使用DDD这样的架构 ...

  6. Easyui datagrid加载本地Json数据,CGI数据

    网上示例(记得引用Jquery): [html] view plaincopy var jsonstr = '{"total":1,"rows":[{" ...

  7. MySQL中RESET SLAVE和RESET MASTER的区别

    RESET SLAVE的语法如下: RESET SLAVE [ALL] [channel_option] channel_option: FOR CHANNEL channel 其中,channel_ ...

  8. slf4j log4j logback关系详解和相关用法

    slf4j log4j logback关系详解和相关用法 写java也有一段时间了,一直都有用slf4j log4j输出日志的习惯.但是始终都是抱着"拿来主义"的态度,复制粘贴下配 ...

  9. 【集合框架】JDK1.8源码分析之Comparable && Comparator(九)

    一.前言 在Java集合框架里面,各种集合的操作很大程度上都离不开Comparable和Comparator,虽然它们与集合没有显示的关系,但是它们只有在集合里面的时候才能发挥最大的威力.下面是开始我 ...

  10. Linux上的SQL Server的起步

    我们知道,几个星期前,微软发布了在Linux上直接运行的SQL Server第一个公开CTP版本!因此,对我来说,是时候跨界在Linux上安装我的第一个SQL安装,这样的话,我就可以在Linux上折腾 ...