关闭。这个问题需要更加集中。它目前不接受答案。想改进这个问题?更新问题,使其仅通过编辑此帖子专注于一个问题。 8年前关闭。改进这个问题
我还没有使用 ARC,因为我目前正在处理的项目中的大部分代码都是在 iOS 5.0 之前编写的。
我只是想知道,不手动保留/释放的便利(以及由此产生的更可靠的代码?)是否超过使用 ARC 的任何“成本”?您对 ARC 的体验如何,您会推荐它吗?
所以:
ARC能为一个项目带来多少好处?
ARC 是否有像 Java 中的垃圾收集一样的成本?
您是否一直在使用 ARC,如果是,到目前为止您是如何找到它的?
没有缺点。用它。今天就去做。它比您的旧代码更快。它比您的旧代码更安全。它比您的旧代码更容易。这不是垃圾收集。它没有 GC 运行时开销。编译器在您应该拥有的所有地方插入保留和释放。但它比你更聪明,可以优化那些实际上不需要的(就像它可以展开循环、消除临时变量、内联函数等)
好的,现在我将告诉您一些小缺点:
如果你是一个长期的 ObjC 开发者,当你看到 ARC 代码时,你会抽搐大约一周。你会很快克服这一点。
桥接到 Core Foundation 代码有一些(非常)小的复杂性。处理将 id 视为 void* 的任何事情都会稍微复杂一些。像 C-arrays of id 这样的事情可能需要更多的思考才能正确完成。 ObjC va_args 的花哨处理也会引起麻烦。大多数涉及 ObjC 指针上的数学运算的事情都比较棘手。在任何情况下,你都不应该拥有太多这样的东西。
您不能将 id 放入结构中。这是相当罕见的,但有时它被用来打包数据。
如果您没有遵循正确的 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,永远不要回头。
编辑
我已经看到了一些类似“使用 ARC 不能替代了解 Cocoa 内存管理规则”的评论。这大部分是正确的,但重要的是要了解为什么以及为什么不这样做。首先,如果您的所有代码都使用 ARC,并且您到处都违反了 Three Magic Words,那么您仍然没有问题。令人震惊的说,但你去。 ARC 可能会保留一些您并不打算保留的东西,但它也会释放它们,所以这无关紧要。如果我今天在 Cocoa 中教授一门新课程,我可能会在实际的内存管理规则上花费不超过五分钟的时间,而且在讨论 KVC 命名时我可能只会提到内存管理命名规则。有了 ARC,我相信你完全可以在不学习内存管理规则的情况下成为一个体面的初级程序员。
但是你不能成为一个像样的中级程序员。您需要了解规则才能正确地与 Core Foundation 桥接,并且每个中级程序员都需要在某些时候处理 CF。并且您需要了解混合 ARC/MRC 代码的规则。当您开始使用指向 id
的 void*
指针时,您需要了解规则(您仍然需要正确执行 KVO)。还有块......好吧,块内存管理很奇怪。
所以我的观点是,底层的内存管理仍然很重要,但是我曾经花费大量时间为新程序员陈述和重申规则,而 ARC 正在成为一个更高级的话题。我宁愿让新开发人员从对象图的角度来思考,而不是让他们的头脑充满对 objc_retain()
的底层调用。
比我的更好,更多的技术答案会出现,但这里有:
ARC != 垃圾回收。没有运行时惩罚,它是在编译时完成的。
正如您在评论中建议的那样,ARC 也 != 只是自动发布所有内容。阅读文档
一旦你意识到你做了多少手动参考管理,那就太棒了
用它!
一个缺点 - 维护旧的非弧代码突然变得非常乏味。
ARC能为一个项目带来多少好处?
好处是可以显着防止常见的内存管理错误。应显着减少因未能释放对象而导致的泄漏和因未能保留或过早释放对象而导致的崩溃。您仍然需要了解引用计数内存模型,以便您可以将引用分类为强引用或弱引用,避免保留循环等等。
垃圾收集真正的“成本”是多少?
iOS 中没有垃圾收集。 ARC 类似于 GC,因为您不必手动保留或释放对象。它与 GC 不同之处在于没有垃圾收集器。保留/释放模型仍然适用,只是编译器在编译时将适当的内存管理调用插入到您的代码中。
您是否一直在使用 ARC,如果是,到目前为止您是如何找到它的?
如果您习惯于引用计数,这有点令人不安,但这只是习惯它并学会相信编译器真的会做正确的事情的问题。这感觉就像是 Objective-C 2.0 带来的属性变化的延续,这是朝着简化内存管理迈出的又一大步。如果没有手动内存管理调用,您的代码会变得更短且更易于阅读。
ARC 的唯一问题是旧版本的 iOS 不支持它,因此您需要在决定采用它之前考虑到这一点。
我认为 ARC 是个好主意。与GC相比,你可以吃蛋糕也可以吃。我倾向于相信 MRC 对内存管理强加了一个非常宝贵的“纪律”,每个人都会从中受益。但我也同意需要注意的真正问题是对象所有权和对象图(正如许多人指出的那样),而不是低级引用计数本身。
总结一下:ARC 不是对记忆无动于衷的免费通行证;它是一种帮助人类避免重复任务的工具,这些任务会导致压力并且容易出错,因此更好地委托给机器(在这种情况下是编译器)。
也就是说,我个人是一个工匠,还没有过渡。我刚开始使用Git...
更新:所以我迁移了我的整个游戏,包括 gl 库,到目前为止没有问题(Xcode 4.2 中的迁移助手除外)。如果你正在开始一个新项目,那就去做吧。
我在几个(诚然很小的)项目中使用过它,而且我只有很好的经验,无论是性能还是可靠性方面。
需要注意的一点是,如果你自己编写 UI,你需要学习弱引用的 do:s 和 don't:s 不会导致任何引用循环,设计师往往会做得很好如果您使用它设置您的 GUI,则会自动执行此操作。
我遇到的唯一缺点是,如果您使用包含大量 CoreFoundation 函数和数据的库。在 MRC 中,您不必担心使用 CFStringRef
而不是 NSString*
。在 ARC 中,您必须指定两者如何交互(基本桥接?释放 CoreFoundation 对象并将其移动到 ARC?将 Cocoa 对象作为 +1 CoreFoundation 保留对象?)此外,在 OS X 上,它仅适用于 64-位代码(虽然我确实有一个可以解决这个问题的标题......)。
不定期副业成功案例分享