到 ARC 还是不到 ARC? 优点和缺点是什么?

我还没有使用 ARC,因为我目前正在开发的项目中的大部分代码都是在 iOS 5.0之前编写的。

I was just wondering, does the convenience of not retaining/releasing manually (and presumably more reliable code that comes as a result?) outweigh any 'cost' of using ARC? 你对 ARC 有什么经验,你会推荐它吗?

所以:

  • ARC 能给一个项目带来多少好处?
  • ARC 在 Java 中是否有类似垃圾收集的成本?
  • 你一直在使用 ARC 吗? 如果是的话,你是如何找到它的?
23447 次浏览

比我的更好,更技术性的答案将会出现,但这里有:

  • ARC! = 垃圾收集。没有运行时损失,它是在编译时完成的。
  • 就像你在评论中建议的那样,自动发布一切。阅读 医生
  • 这是令人敬畏的一旦你意识到多少手动参考管理你 曾经是
  • 用它!
  • 一个缺点是,维护旧的、非弧形的代码突然变得非常单调乏味。

I've used it in a couple of (admittedly small) projects, and I have only good experiences, both performance- and reliability wise.

需要注意的一点是,如果你自己编写用户界面,你需要学习弱引用的“做”和“不做”,以免引起任何引用循环。如果你使用它来设置你的 GUI,设计师倾向于自动完成这项工作。

How much benefit can ARC bring to a project?

这样做的好处是可以在很大程度上避免常见的内存管理错误。因未能释放物体而造成的泄漏以及因未能保留或过早释放物体而导致的崩溃应大大减少。您仍然需要理解引用计数内存模型,以便能够将引用分类为强或弱、避免保留循环等等。

垃圾收集到底“花费”多少?

在 iOS 中没有垃圾回收。ARC 类似于 GC,因为您不必手动保留或释放对象。它不同于 GC,因为它没有垃圾收集器。保留/释放模型仍然适用,只是编译器在编译时为您在代码中插入适当的内存管理调用。

Have you been using ARC and if so, how have you found it so far?

如果您习惯于引用计数,那么这会有点令人不安,但这只是一个习惯的问题,并且学会相信编译器真的会做正确的事情。它感觉像是 Objective-C2.0对属性的改变的延续,这是简化内存管理的又一大步。如果没有手动内存管理调用,代码就会变得更短、更容易阅读。

ARC 的唯一问题是旧版本的 iOS 不支持它,所以在决定采用它之前,你需要考虑到这一点。

There is no downside. Use it. Do it today. It is faster than your old code. It is safer than your old code. It is easier than your old code. It is not garbage collection. It has no GC runtime overhead. The compiler inserts retains and releases in all the places you should have anyway. But it's smarter than you and can optimize out the ones that aren't actually needed (just like it can unroll loops, eliminate temporary variables, inline functions, etc.)

OK, now I will tell you about the small downsides:

  • 如果您是一名长期的 OBC 开发人员,那么当您看到 ARC 代码时,您将会抽搐一周左右。你很快就会克服的。

  • 在连接到核心基础代码方面有一些(非常)小的复杂性。在处理任何将 id作为 void*对待的事情时,都会有稍微复杂一些的情况。像 id的 C 数组这样的事情可能需要更多的思考才能正确完成。花哨的处理对象 va_args也会引起麻烦。大多数涉及到对一个对象指针进行数学处理的事情都比较棘手。无论如何你都不应该有这么多。

  • You cannot put an id in a struct. This is fairly rare, but sometimes it's used to pack data.

  • 如果您没有遵循正确的 KVC 命名,并且您混合了 ARC 和非 ARC 代码,您将有内存问题。ARC 使用 KVC 命名来决定内存管理。如果都是 ARC 代码,那就无所谓了,因为它在两边都会做同样的“错误”。但如果它是混合 ARC/非 ARC,那么就有一个不匹配。

  • 在对象异常抛出期间,ARC 将泄漏内存。对象异常应该非常接近程序的终止时间。如果您捕获了大量的对象控制异常,那么您就是在错误地使用它们。使用 -fobjc-arc-exceptions可以解决这个问题,但它会招致以下讨论的惩罚:

  • ARC will not leak memory during ObjC or C++ exception throws in ObjC++ code, but this is at the cost of both time and space performance. This is yet another in a long list of reasons to minimize your use of ObjC++.

  • ARC 将不能在 iPhoneOS3或 Mac OSX 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 教一门新课,我可能不会花超过5分钟的时间来讲解实际的内存管理规则,而且在讨论 KVC 命名时,我可能只会提到内存管理命名规则。使用 ARC,我相信你实际上不需要学习任何内存管理规则就可以成为一个优秀的初级程序员。

但是你不可能成为一个优秀的中级程序员。您需要了解规则,以便正确地与核心基础架起桥梁,并且每个中级程序员都需要在某个时候处理 CF。您需要了解混合 ARC/MRC 代码的规则。当您开始使用指向 idvoid*指针(您仍然需要正确地执行 KVO)时,您需要了解规则。还有块... 块内存管理很奇怪。

So my point is that the underlying memory management is still important, but where I used to spend significant time stating and restating the rules for new programmers, with ARC it is becoming a more advanced topic. I'd rather get new developers thinking in terms of object graphs rather than fill their heads with the underlying calls to objc_retain().

我觉得 ARC 是个好主意。与 GC 相比,你既可以吃蛋糕,也可以吃蛋糕。我倾向于认为 MRC 对于内存管理强加了一个无价的“纪律”,每个人都会从中受益。 但我也同意,真正需要注意的问题是对象所有权和对象图(正如许多人指出的) ,而不是低级引用计数本身。

To conclude: ARC is NOT a free pass to be mindless about memory; it is a tool to help humans avoid repetitive tasks, that cause stress and are prone to error, therefore better delegated to a machine (the compiler, in this case).

也就是说,我个人是一个工匠,还没有做出转变。我刚开始使用 Git..。

更新: 所以我迁移了我的整个游戏,包括 gl 库,到目前为止没有问题(除了 Xcode 4.2中的迁移助手)。如果你正在开始一个新的项目,那就去做吧。

我遇到的唯一缺点是如果使用包含大量 CoreFoundation 函数和数据的库。在 MRC 中,您不需要担心使用 CFStringRef而不是 NSString*。在 ARC 中,您必须指定两者如何交互(基本的桥接?释放 CoreFoundation 对象并将其移动到 ARC?将 Cocoa 对象作为 + 1 CoreFoundation 保留对象?)而且,在 OS X 上,它只能在64位代码上使用(尽管我有一个可以绕过这个问题的头文件... ...)。