【问题标题】:To ARC or not to ARC? What are the pros and cons? [closed]ARC还是不ARC?优缺点都有什么? [关闭]
【发布时间】:2012-02-04 08:03:26
【问题描述】:

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

我只是想知道,不手动保留/释放的便利(以及由此产生的更可靠的代码?)是否超过使用 ARC 的任何“成本”? 您对 ARC 有哪些体验,您会推荐它吗?

所以:

  • ARC 可以为项目带来多少好处?
  • ARC 是否像 Java 中的垃圾回收一样有成本?
  • 您是否使用过 ARC,如果使用过,到目前为止您是如何找到它的?

【问题讨论】:

  • ipad/ios 上没有垃圾回收。你说的是 OS X 吗?
  • 抱歉,我使用了不合适的 Java 术语。我的意思是,使用 ARC,对象可以在内存中保存的时间超过必要的时间,然后在一段时间后作为一个组在自动释放池中释放。正是这种效果,它们与其他对象一起被保留和释放,类似于我所指的 Java 的垃圾收集。
  • @TenementFunster,对于相同的代码(减去对释放的调用),ARC 将持有对象的时间不会超过非 ARC 代码。实际上,它通常会比您更快地发布它。有少量的东西有点慢,但它们加速了常见的模式,以至于它对性能的影响相形见绌。对于许多常见模式(例如,保留一个通过自动释放返回的对象),您实际上无法像 ARC 那样快速地手动编写它。

标签: iphone objective-c ipad ios5 automatic-ref-counting


【解决方案1】:

没有缺点。用它。今天就去做。它比您的旧代码更快。它比您的旧代码更安全。它比您的旧代码更容易。这不是垃圾收集。它没有 GC 运行时开销。编译器在您应该拥有的所有地方插入保留和释放。但它比你更聪明,可以优化掉那些实际上不需要的(就像它可以展开循环、消除临时变量、内联函数等)

好的,现在我将告诉你一些小缺点:

  • 如果您是长期的 ObjC 开发人员,当您看到 ARC 代码时,您会抽搐大约一周。你会很快克服这个问题的。

  • 桥接核心基础代码有一些(非常)小的复杂性。处理将id 视为void* 的任何事情都会稍微复杂一些。 id 的 C 数组之类的事情可能需要更多的思考才能正确完成。 ObjC va_args 的花哨处理也会引起麻烦。大多数涉及 ObjC 指针上的数学运算的事情都比较棘手。无论如何,你不应该有太多这样的事情。

  • 您不能将id 放入struct。这种情况相当少见,但有时用于打包数据。

  • 如果您没有遵循正确的 KVC 命名,并且将 ARC 和非 ARC 代码混用,则会出现内存问题。 ARC 使用 KVC 命名来决定内存管理。如果都是 ARC 代码,那没关系,因为它会在双方都做同样的“错误”。但如果它是 ARC/非 ARC 的混合,那就是不匹配。

  • ARC 将在 ObjC 异常抛出期间泄漏内存。 ObjC 异常应该非常接近程序终止的时间。如果您捕获了大量的 ObjC 异常,则说明您使用它们不正确。这可以使用-fobjc-arc-exceptions 解决,但会招致下面讨论的惩罚:

  • 在 ObjC++ 代码中抛出 ObjC 或 C++ 异常期间,ARC 不会泄漏内存,但这是以时间和空间性能为代价的。这是尽量减少使用 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,永远不要回头。


编辑

我见过几个 cmet 类似“使用 ARC 不能替代了解 Cocoa 内存管理规则”。这大部分是正确的,但重要的是要了解为什么以及为什么不这样做。首先,如果您的所有代码都使用 ARC,并且您到处都违反了Three Magic Words,那么您仍然没有问题。令人震惊的说,但你去。 ARC 可能会保留一些您并不打算保留的东西,但它也会释放它们,所以这无关紧要。如果我今天在 Cocoa 中教授一门新课程,我可能会在实际的内存管理规则上花费不超过五分钟的时间,而且在讨论 KVC 命名时我可能只会提到内存管理命名规则。有了 ARC,我相信你完全可以在不学习内存管理规则的情况下成为一个体面的初级程序员。

但是你不能成为一个像样的中级程序员。您需要了解规则才能正确地与 Core Foundation 桥接,并且每个中级程序员都需要在某些时候处理 CF。并且您需要了解混合 ARC/MRC 代码的规则。当您开始使用指向idvoid* 指针(您仍然需要正确执行KVO)时,您需要了解规则。还有块......好吧,块内存管理很奇怪。

所以我的观点是,底层内存管理仍然很重要,但我过去常常花费大量时间为新程序员陈述和重申规则,而 ARC 正在成为一个更高级的话题。我宁愿让新开发人员从对象图的角度来思考,而不是让他们的头脑充满对objc_retain() 的底层调用。

【讨论】:

  • 需要非常小心的一件事(在非 ARC 中也是如此,但在 ARC 中更是如此,因为它现在是如此不可见)是保留周期。我的建议是 1) 如果您发现自己将 objc 块存储为实例变量,请仔细查看它是否可以捕获它是 ivar 的对象,甚至是间接的。 2)实际设计你的对象图,而不是让它发生。如果你想写出好的代码,你必须知道什么拥有什么。 3)使用heapshots:friday.com/bbum/2010/10/17/…
  • @Catfish_Man 所有的优点。保持循环一直是个问题。 Apple 的新建议与您在 #2 中所说的完全一样。我们需要考虑对象图而不是保留和释放。 #1 是块的严重问题,也是我发现块是喜忧参半的几个原因之一,应该谨慎处理。
  • 有一个没有提到的严重缺点:交叉兼容性。对于我们勇敢而愚蠢的人来说,面对被称为跨平台编程的荒地,ARC 根本不是一种选择,至少在 GNU 再次扩展其 ObjC 运行时和编译器功能之前(他们说更多即将推出)。
  • 您可以使用 ARC,但需要支持 iOS 3.x 设备。顺便说一句,确保使用 Xcode 进行转换(编辑 > 重构 > 转换为 Objective-C ARC)。在此过程中,Xcode 会进行大量验证,以确保您的代码能够正常工作并找出任何违反这些设计准则的代码。
  • 优秀.. 逐点回答。这是我的第 100 个。祝贺一个世纪;)
【解决方案2】:

会有比我更好、更多技术性的答案,但这里是:

  • ARC != 垃圾回收。没有运行时损失,它是在编译时完成的。
  • ARC 也 != 只是自动释放所有内容,正如您在评论中所建议的那样。阅读docs
  • 一旦您意识到自己做了多少手动参考管理工作,那真是太棒了
  • 使用它!
  • 一个缺点 - 维护旧的非弧代码突然变得非常乏味。

【讨论】:

  • 是的,这就是我到目前为止没有使用它的原因 - 我不确定我是否能忍受通过我们大量的预先存在的代码来转换它......我肯定会尝试下一个项目。谢谢你的回答:)
  • 不是维护旧代码变得更加困难,而是您的期望发生了变化。因此,责怪 ARC 让生活变得更轻松是不公平的。 Xcode 可以在您准备好后轻松将旧代码转换为 ARC,但如果您仍需要支持较旧的 iOS 版本,您显然无法使用它。
  • @Caleb 我并没有责怪 ARC,这只是我迄今为止看到的唯一缺点 - 它在一个项目的空间里把我宠坏了。
  • 是的;我没有将其列为问题,但是当您必须在代码库之间切换时,会出现一个退出内存管理实践的小问题。我的一些项目在 10.4 上运行,所以我仍然做很多 Objective-C 1.0 的工作(所以没有@synthesize,更不用说 ARC)。但是你已经习惯了切换模式。
  • @jrturton 我应该更清楚地说明,我写这篇文章是为了 OP 和可能不了解 ARC 所做的未来读者的利益。我完全明白你的意思,只是不想让任何人得出混合 ARC 和非 ARC 代码会产生问题的错误结论。
【解决方案3】:

ARC 能为项目带来多少好处?

好处是可以显着防止常见的内存管理错误。应显着减少因未能释放对象而导致的泄漏和因未能保留或过早释放对象而导致的崩溃。您仍然需要了解引用计数内存模型,以便将引用分类为强引用或弱引用,避免保留循环等等。

垃圾回收真正的“成本”是多少?

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

您是否使用过 ARC,如果使用过,到目前为止您是如何找到它的?

如果您习惯于引用计数,这有点令人不安,但这只是习惯它并学会相信编译器确实会做正确的事情的问题。这感觉就像是 Objective-C 2.0 中属性变化的延续,这是朝着简化内存管理迈出的又一大步。如果没有手动内存管理调用,您的代码会变得更短且更易于阅读。

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

【讨论】:

  • 我说的是更好的答案!
  • 是的,很好的答案。那么除了必须学会相信它的工作原理之外,ARC 真的没有缺点吗?在那种情况下似乎好得令人难以置信?
【解决方案4】:

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

总结一下:ARC 并不是对记忆无动于衷的免费通行证;它是一种帮助人类避免重复性任务的工具,这些任务会导致压力并容易出错,因此更好地委托给机器(在这种情况下是编译器)。

也就是说,我个人是一个工匠,还没有过渡。我刚开始使用 Git...

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

【讨论】:

    【解决方案5】:

    我在几个(诚然很小的)项目中使用过它,我只有很好的经验,无论是性能还是可靠性方面。

    需要注意的一点是,如果您自己编写 UI,那么您需要了解弱引用的 do:s 和 dont:s,以免造成任何引用循环,设计师往往会做得很好如果您使用它设置 GUI,它会自动完成。

    【讨论】:

      【解决方案6】:

      我遇到的唯一缺点是,如果您使用包含大量 CoreFoundation 函数和数据的库。在 MRC 中,您无需担心使用 CFStringRef 而不是 NSString*。在 ARC 中,您必须指定两者如何交互(基本桥?释放 CoreFoundation 对象并将其移动到 ARC?将 Cocoa 对象作为 +1 CoreFoundation 保留对象?)此外,在 OS X 上,它仅适用于 64-位代码(虽然我确实有一个可以解决这个问题的标题......)。

      【讨论】:

        猜你喜欢
        • 2011-12-14
        • 1970-01-01
        • 2012-02-03
        • 1970-01-01
        • 1970-01-01
        • 2014-06-26
        • 1970-01-01
        • 1970-01-01
        • 2011-04-01
        相关资源
        最近更新 更多