iOS开发之ARC(自动引用计数) 已翻译 100%

JoeyBlue 投递于 2013/02/20 10:40 (共 18 段, 翻译完成于 02-27)
阅读 14916
收藏 47
4
加载中

自动引用计数(ARC)是在MacOS X 10.7与iOS 5中引入一项新技术,用于管理Objective-C中的对象。它废弃了显式的retain、release和autorelease消息,而且在两个平台的表现一致。

由于有限的内存以及手持设备续航能力的限制,iOS应用程序中的Objective-C对象的管理一直颇有挑战性。为了处理这些问题,苹果提出了一个方案——“自动引用计数”(ARC)。在这篇文章中,我会把ARC和显式的retain/release以及垃圾回收进行对比,除此之外还会展示如何在一个iOS项目中使用它,并且探讨一些ARC的使用准则。

读者应当拥有Objective-C和Xcode IDE的使用经验。

MuhammadW
MuhammadW
翻译于 2013/02/24 04:08
2

通过消息传送来实现

首先,我通过显示的消息传送来管理ObjC对象。我用alloc和init消息来创建对象(如图 1)。我发送retain消息来保持一个对象,并且发送release消息来释放掉它。通过alloc/init创建的ObjC对象会有一个内部的值为1的引用计数。retain消息会使这个引用计数加1,然而,release消息会使这个引用计数减1.当这个引用计数为0时,这个对象会自动销毁,释放它所持有的内存。


Figure 1.


我们也可以用一个工厂方法来创建ObjC对象。这样就标记了这个对象是自动释放的,将他的指针加到自动释放池(如图 2)。我们可以通过autorelease消息来实现对alloc/init的对象达到发送release消息的目的。


Figure 2.

李远超
李远超
翻译于 2013/02/25 11:27
2

在每一个事件周期中,自动释放内存池都会去检测自身的对象指针集。当它发现超出其作用域并且引用记数为1的对象,它就会通过发送一个release消息释放这个对象。当不想释放这个对象时,我们可以发送一个或多个retain消息给这个对象。否则,我们必须让这个对象发送的retain和release消息一样多,才能将它释放。

显式发送消息的方式仍然是iOS应用程序中管理ObjC对象的一种有效方法。它一般不会花费很多精力,可以很容易的定位bug,同时拥有性能好的特点。

在另一方面,显式发送消息的方式很容易导致出错。当retain和release消息不相等时,它会导致内存泄露或EXC_BAD_ACCESS错误。另外,显式地释放一个已经释放了的对象也会导致EXC_BAD_ACCESS错误。并且,对象容器(如数组,集合等)可能并不会对它包含的引用记数大于1的对象运行该对象的构造函数。
showme
showme
翻译于 2013/02/25 15:02
2

使用垃圾回收管理

MacOS X 10.5 (Leopard) 给我们另一个管理ObjC对象的方法— 垃圾回收。这里,每一个Cocoa应用程序得到自己的作为次级线程运行的收集服务  (Figure 3)。


Figure 3.

这个服务标识所有在一起动就创建的根对象,然后跟踪每一个后来创建的对象。它检查每一个对象的范围以及对根对象的强引用。如果对象有这些特性,那么收集服务将它保留下来(用蓝色标记)。否则,它使用一个finalize消息释放这个对象(用红色标记)。

纶巾客
纶巾客
翻译于 2013/02/25 15:25
2

收集服务是保守的。当必须保证高性能时,它可以被中断,甚至暂停 。它是一个分代的服务。他假定最新被创建的对象寿命最短。

通过类NSGarbageCollector来使用收集服务。使用这个类,我能够禁用这个服务或者改变它的行为。我甚至能指定新的根对象或者重置服务本身。


垃圾回收移除了显式的保留和释放消息的需要。它能够降低野指针也能够防止空指针。换句话说,它需要所有定制的ObjC对象被更新。清除代码必须进入到finalize方法,而不是 dealloc方法。ObjC对象也必须向他的父发送一个finalize消息。

接下来,收集服务需要知道何时一个对象的引用是弱的。否则,他假设所有的引用都是强的。这可能导致循环引用和内存泄漏。这个服务也忽略使用withmalloc()创建的对象:那些对象应该被手动释放或者使用Cocoa函数NSAllocateCollectable()来创建。

最后,这个服务依然会导致性能受到影响,尽管他是保守的。这就是垃圾回收在iOS上缺席的原因。

纶巾客
纶巾客
翻译于 2013/02/25 16:21
4

进入 ARC

ARC是一种全新的方式,它拥有很多垃圾回收机制的优点,但却没有那样的性能损耗。

从内部来看,ARC并不是一项运行时的服务。实际上它是由新的Clang front-end提供的两段过程。图4显示了这两段过程。在front-end段时,Clang检查每个预处理文件的对象和属性。然后它跟据一些固定的规则将正确的retain,release和autorelease语句加入其中。

图4.

举例来说,如果对象被分配内存并处于一个方法当中,它会在这个方法的结尾处获得一个release语句。如果是一个类属性,它的release语句会加入到类的dealloc方法中。如果这个对象是用来返回的或者它是一个容器对象,它会加入一个autorelease语句。又如果这个对象是弱引用,把它放在一边不管它。

showme
showme
翻译于 2013/02/25 16:02
3

前端也为非局部对象插入保留语句。他更新所有使用@property指示符声明的访问器。他添加了对父的dealloc的调用,并且他报告任何的显式的管理调用和任何不清晰的所有权。

在优化阶段,Clang 使修改过的代码遵从加载平衡。它统计每一个对象保留和释放的调用,然后把它们缩减到优化的最小值。这避免了过度的保留和释放,能够在性能上产生影响。

为了描述, 看看在Listing One中的实例代码。

Listing One

@class Bar;
@interface Foo
{
@private
    NSString *myStr;
}
@property(readonly) NSString *myStr;
 
- (Bar *)foo2Bar:(NSString *)aStr;
- (Bar *)makeBar;
//...
@end
 
 
@implementation Foo;
@dynamic myStr;
 
– (Bar *)foo2Bar:(NSString *)aStr
{
    Bar *tBar;
     
    if (![self.myStr isEqualToString:aStr])
    {
        myStr = aStr;
    }   
    return ([self makeBar]);
}
 
- (Bar *)makeBar
{
    Bar *tBar
    //...
    //... conversion code goes here
    //...
    return (tBar);
}
//...
@end
在这里,我展示了一个没有任何保留和释放消息的ObjC类。它有一个私有的属性myStr,它是一个NSString(第5行)的实例.它声明了一个只读的getter, 也命名为myStr(第7行).它定义了一个修饰符foo2Bar和一个内部函数makeBar(18-36行)。这个类也使用@class指示符导入了类Bar的header(第1行)。 
纶巾客
纶巾客
翻译于 2013/02/25 21:10
2

列表2列出了相同简单的经过ARC处理后的代码。

列表2

@class Bar;
@interface Foo
{
@private
    NSString *myStr;
}
@property (readonly) NSString *myStr;
 
- (Bar *)foo2Bar:(NSString *)aStr;
- (Bar *)makeBar;
//...
@end
 
 
@implementation Foo;
@dynamic myStr;
 
– (Bar *)foo2Bar:(NSString *)aStr
{
    Bar *tBar;
     
    if (![self.myStr isEqualToString:aStr])
    {
        [aStr retain];
        [myStr release];
        myStr = aStr;
    }   
    return ([self makeBar]);
}
 
- (Bar *)makeBar
{
    Bar *tBar
    //...
    //... conversion code goes here
    //...
    [tBar autorelease];
    return (tBar);
}
//...
 
- (void)dealloc
{
    [myStr release];
    [super dealloc];
}
@end
类接口并没有被改变。但是它的foo2Bar被新加入了两行代码。一个语句发送一个release消息给属性myStr(行24)。另一个发送一个retain消息给参数aStr(行25)。makeBar函数在返回之前发送一个autorelease消息给局部变量tBar,并将tBar作为返回值。最后,ARC重写了类的dealloc方法。在这个方法中,它释放了属性myStr(行44)并且调用父类的dealloc方法(行45)。如果一个dealloc方法已经存在,ARC会将它的代码作适当更新。
showme
showme
翻译于 2013/02/26 12:02
2

因为ARC独自决定ObjC对象如何被管理,它省掉了开发类代码的时间。它阻止了任何野指针和空指针。它甚至能够基于文件来禁用。最后一个特征让程序员可以复用被证明是稳定的遗留代码。

但是Clang编译器被构建在LLVM 3.0中,它只能在Xcode 4.2或者更新的版本中获得.对于ARC的优化的运行时支持也仅仅出现在MacOS X 10.7 (Lion) 和 iOS 5.0。在iOS 4.3中通过粘合代码使用ARC是可能的。在后来提供的不使用任何弱指针的二进制文件中使用ARC也是可能的。

然后,ARC只对ObjC代码起作用。对于PyObjC和AppleScriptObjC代码没有任何效果。但是,它的确影响那些桥接PyObjC,ASOC类到Cocoa的底层ObjC对象。也值得注意的是,一些第三方的框架在使用ARC开启的编译的时候也可能会导致问题 。请确保在更新版本时联系框架的开发者。


纶巾客
纶巾客
翻译于 2013/02/26 15:04
2

为ARC做准备

在一个iOS项目中有两个方法支持ARC。一个是使用ARC-enabled的模板创建项目。另一个是使用Xcode改写一个现存的项目。

假设你想开始一个新的iOS项目。启动Xcode,从文件菜单里选择新项目。在新建对话框中 (Figure 5),选择一个项目模板(在这个例子中,单视图项目),点击Next查看项目选项。在界面的字段中输入项目名称,公司ID,以及类前缀。 然后勾选Use Automatic Reference Counting (Figure 6). 点击Next查看项目位置。设置位置和源代码仓库 (可选),然后点击Create创建项目本身。


Figure 5.


Figure 6.

为了验证ARC是否被开启,在项目窗口中的组和文件面板中选择项目图标 (Figure 7).从Target Setting工具条中点击Build Settings。,然后点击那个工具条下边的All。向下滚动并且定位到设置组Apple LLVM computer 3.0 — Language。 查找条目Objective-C Automatic Reference Counting — 它的值应该是Yes.


Figure 7.

纶巾客
纶巾客
翻译于 2013/02/25 22:44
2
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(15)

乐天涯
乐天涯

arc再iOS5以上的系统上可以运行么?具体怎么搞阿

HuangHector
HuangHector
这篇文章谷歌翻译的气息很浓
HuangHector
HuangHector

引用来自“HuangHector”的评论

Figure 1,retainCount为3的时候,为什么发送一条release消息后就变成1了,难道不应该是2么?

Figure 2也有同样的问题
HuangHector
HuangHector
Figure 1,retainCount为3的时候,为什么发送一条release消息后就变成1了,难道不应该是2么?
疯人院主任
疯人院主任
参考列表在那里
金三胖
金三胖

引用来自“大白良”的评论

引用来自“流风回雪”的评论

Objective-C让我学得十分别扭,看来我是搞不起iOS了
求高人指点下android开发如何入门,目前是拍黄片的,没有什么java基础
最好推荐本相关的教材

写惯了php的人,对内存管理都不适应,其实java也会有内存优化的问题,写android也避免不了

嗯,我慢慢适应
哈哈哈哈哈哈笑
哈哈哈哈哈哈笑

引用来自“流风回雪”的评论

Objective-C让我学得十分别扭,看来我是搞不起iOS了
求高人指点下android开发如何入门,目前是拍黄片的,没有什么java基础
最好推荐本相关的教材

写惯了php的人,对内存管理都不适应,其实java也会有内存优化的问题,写android也避免不了
kut
kut
其实用惯了OBJC,也觉得这个语言也有可取之处的,特别是它的简单,会C的人很快就能入手。
AlfredCheung
AlfredCheung

引用来自“流风回雪”的评论

Objective-C让我学得十分别扭,看来我是搞不起iOS了
求高人指点下android开发如何入门,目前是拍黄片的,没有什么java基础
最好推荐本相关的教材

学过java的表示Objective-C不难..而且有了ARC真的很方便
AlfredCheung
AlfredCheung

引用来自“流风回雪”的评论

引用来自“AlfredCheung”的评论

拍黄片的?-.-

PHP (*^__^*)

o.o!长知识了...
返回顶部
顶部