我目前在工作的项目中使用的大部分代码都是在 iOS 5.0 之前编写的,因此我尚未使用 ARC。
我只是想知道,不需要手动保留/释放对象是否更便捷(并且伴随着更可靠的代码),这是否会抵消使用 ARC 的任何“成本”?您使用 ARC 的经验如何?是否推荐使用 ARC?
因此:
- ARC 可以给项目带来多少好处?
- 与 Java 中的垃圾回收一样,ARC 是否有成本?
- 您是否一直在使用 ARC?如果是,迄今为止您的使用经验如何?
我目前在工作的项目中使用的大部分代码都是在 iOS 5.0 之前编写的,因此我尚未使用 ARC。
我只是想知道,不需要手动保留/释放对象是否更便捷(并且伴随着更可靠的代码),这是否会抵消使用 ARC 的任何“成本”?您使用 ARC 的经验如何?是否推荐使用 ARC?
因此:
没有缺点。使用它。今天就开始使用。它比你的旧代码更快。它比你的旧代码更安全。它比你的旧代码更容易。它不是垃圾收集。它没有GC运行时开销。编译器会在所有应该有的地方插入保留和释放代码。但它比你聪明,可以优化掉实际上不需要的部分(就像可以展开循环、消除临时变量、内联函数等一样)。
好的,现在我会告诉您一些小缺点:
如果您是长期使用ObjC开发者,当您看到ARC代码时,您会感觉不适约一周时间。但您很快就会克服这个问题。
与Core Foundation代码桥接时可能存在一些(非常)小的复杂性。处理任何将id
视为void*
的内容会稍微复杂一些。例如,id
类型的C数组需要考虑更多细节才能正确处理。复杂的ObjCva_args
处理可能也会引起麻烦。大多数涉及ObjC指针的数学计算都较为棘手。不过,在任何情况下,这些因素应该不会有太多问题。
您不能将id
放入struct
中。这种情况非常罕见,但有时会用于数据打包。
如果您没有遵循正确的KVC命名约定,并混合使用ARC和非ARC代码,则可能会发生内存问题。ARC使用KVC命名来确定内存管理方式。如果都是ARC代码,则无关紧要,因为它会在两侧都执行相同的“错误”操作。但如果混合使用ARC /非ARC,则会出现不匹配。
在ObjC异常抛出期间,ARC会泄漏内存。ObjC异常应该非常接近程序的终止时间。如果您捕获了大量ObjC异常,则使用方式不正确。可以通过使用-fobjc-arc-exceptions
进行修复,但会产生下面讨论的惩罚:
在ObjC++代码中,ARC不会在ObjC或C++异常抛出时泄漏内存,但这是以时间和空间性能为代价的。这是另一个减少使用ObjC++的理由。
ARC在iPhoneOS 3或Mac OS X 10.5或更早版本上根本无法工作。(这使我无法在许多项目中使用ARC。)
__weak
指针在iOS 4或Mac OS X 10.6上无法正常工作,这很遗憾,但相当容易解决。__weak
指针很棒,但它们不是ARC的最大卖点。
对于95%以上的代码来说,ARC非常出色,并且没有任何理由避免使用它(只要您可以处理操作系统版本限制)。对于非ARC代码,您可以按文件传递-fno-objc-arc
。不幸的是,Xcode实际上比应该更难做到这一点。您应该将非ARC代码移动到单独的xcodeproj中,以简化此过程。
总之,尽快切换到ARC,永远不要回头。
编辑
我看到有一些评论说“使用ARC不能替代了解Cocoa内存管理规则”,这基本上是正确的,但重要的是理解原因和不足之处。首先,如果您的所有代码都使用ARC,并且您在各个地方违反了三个魔术词,那么您仍然不会有问题。难以置信,但就是这样。ARC可能会保留您不想保留的一些东西,但它也会释放它们,所以这永远不会成为问题。如果我今天在教授Cocoa新课程,我可能只会在讨论KVC命名时提到内存管理命名规则而不会超过五分钟讲授实际内存管理规则。通过ARC,我相信您甚至可以成为一个不需要学习任何内存管理规则的入门级程序员。
但您无法成为一个合格的中级程序员。您需要知道规则以便与Core Foundation正确连接,每个中级程序员在某个时候都需要处理CF。并且在处理混合ARC / MRC代码时需要知道规则。当您开始玩弄void *
指向id
的指针(您继续需要执行正确的KVO)时,您需要知道规则。块...好吧,块内存管理就是奇怪的。
所以我的观点是,底层内存管理仍然很重要,但是在ARC之前,我花费了大量时间阐述规则以及为新程序员重新说明规则,现在它已成为一个更高级的主题。我宁愿让新开发者考虑对象图而不是填充他们的头脑与对objc_retain()
的基本调用。
ARC能为项目带来多大的好处?
ARC可以显著降低因未释放对象而导致的泄漏和因无法保留或过早释放对象而导致的崩溃。但仍需理解基于引用计数的内存模型,以便分类强引用和弱引用、避免循环引用等。
自动垃圾回收真正的“代价”有多大?
iOS没有垃圾回收机制。ARC类似于垃圾回收,因为你不需要手动保留或释放对象。但与垃圾回收不同的是,没有垃圾回收器。仍然适用保留/释放内存模型,只是编译器在编译时会为你插入相应的内存管理调用。
您是否一直在使用ARC?如果是,迄今为止您的体验如何?
如果您习惯了引用计数,那么使用ARC可能会让人有些不安,但这只是一个适应过程,需要学会信任编译器会自动进行正确的操作。它感觉像Objective-C 2.0引入属性的延续,是简化内存管理的又一大进步。没有手动内存管理调用,您的代码会更短、更易读。
ARC唯一的问题是不支持旧版本的iOS,因此在决定是否采用时需要考虑这一点。
CFStringRef
而不是NSString*
。但在ARC中,您必须指定这两者如何交互(基本桥接?释放CoreFoundation对象并将其移动到ARC?将Cocoa对象作为+1 CoreFoundation保留对象?)。此外,在OS X上,它仅适用于64位代码(尽管我有一个可以解决这个问题的头文件…)。我已经在一些(尽管是小型的)项目中使用它,我的经验非常好,无论是性能还是可靠性方面都很优秀。
一个小小的注意事项是,如果你自己编写UI,你需要学习弱引用的做与不做,以避免引用循环。如果你使用设计师设置GUI,他们通常会自动完成这个工作。