ChatGPT解决这个技术问题 Extra ChatGPT

ARC还是不ARC?优缺点都有什么? [关闭]

关闭。这个问题需要更加集中。它目前不接受答案。想改进这个问题?更新问题,使其仅通过编辑此帖子专注于一个问题。 8年前关闭。改进这个问题

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

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

所以:

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

ARC 是否有像 Java 中的垃圾收集一样的成本?

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

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

S
Schemetrical

没有缺点。用它。今天就去做。它比您的旧代码更快。它比您的旧代码更安全。它比您的旧代码更容易。这不是垃圾收集。它没有 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 代码的规则。当您开始使用指向 idvoid* 指针时,您需要了解规则(您仍然需要正确执行 KVO)。还有块......好吧,块内存管理很奇怪。

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


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

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

ARC != 垃圾回收。没有运行时惩罚,它是在编译时完成的。

正如您在评论中建议的那样,ARC 也 != 只是自动发布所有内容。阅读文档

一旦你意识到你做了多少手动参考管理,那就太棒了

用它!

一个缺点 - 维护旧的非弧代码突然变得非常乏味。


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

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

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

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

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

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

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

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


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

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

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

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

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


J
Joachim Isaksson

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

需要注意的一点是,如果你自己编写 UI,你需要学习弱引用的 do:s 和 don't:s 不会导致任何引用循环,设计师往往会做得很好如果您使用它设置您的 GUI,则会自动执行此操作。


M
MaddTheSane

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