iOS5中强引用和弱引用的解释

117

我是iOS5开发和Objective-C的新手。我不理解strongweak存储之间的区别。我阅读了文档和其他SO问题,但它们对我来说听起来都一样,没有更深入的见解。

我阅读了文档:转换到ARC - 它引用了iOS4中保留、分配和释放的术语;这让我感到困惑。然后我查看了Open U CS193p,它区分了strongweak:

强引用 (Strong): "在我不再指向它之前,请将其保存在堆上"
弱引用 (Weak): "只要有其他人强烈地指向它,就将其保留"

这两个定义难道不是相同的吗 = 如果指针不再指向一个对象,那么释放持有对象的内存?我理解指针、堆、内存的分配或释放的概念 - 但是strongweak之间有什么区别呢?


尽管使用自动引用计数(ARC),内存管理模型仍然很重要。你仍然需要理解引用计数,只是不必手动执行它。因此,你最后一段的要求是不合理的。 - jrturton
https://stackoverflow.com/questions/53699976/memory-management-attribute-when-using-class-type-property-in-objective-c-arc/53703259#53703259 - Arjun Patel
6个回答

513
强引用指向对象的所有强引用都不存在时,该对象将被释放。即使还有弱引用指向它,一旦最后一个强引用消失,对象也将被释放,并且所有剩余的弱引用将被清空。
举个例子,我们的对象是一只狗,这只狗想要逃跑(被释放)。 强引用就像绳索一样,只要你把绳子系在狗身上,狗就不会跑掉。如果五个人把他们的绳子都系在同一只狗身上(即五个强引用指向同一个对象),那么狗在所有五个绳子都脱落之前,都不会跑掉。
另一方面,弱引用就像小孩子指着狗说:“看!一只狗!” 只要狗仍然被拴在绳子上,小孩子们就可以看到狗,并且他们仍然会指着它。 但是,一旦所有绳子都被解开,狗就会跑掉,不管有多少小孩子还在指着它。
一旦最后一个强引用(绳索)不再指向对象,该对象就会被释放,并且所有弱引用都将被清空。

2
这是基于几年前苹果公司的Malcom Crawford提出的类比。不知道他从哪里得到的。 - BJ Homer
15
+1 很棒的例子。这是 Hillegass 提出的关于如何保留/释放绳索的派生示例,但我喜欢这个针对强/弱的改编。 - Dave DeLong
2
@DaveDeLong:在使用ARC的10.6上,它们是非法的。你根本不能使用它们。所以这有点不相关。 - BJ Homer
5
另一个不错的例子是氦气球:只要至少握住一根绳子,它就不会飘走。拿牵狗绳和气球作比喻也有助于让人们忘记“所有权”是由保留/释放来管理的。 - Steve Weller
对于狗的例子加1分,非常令人印象深刻。弱引用应该改为:"只要有其他对象强引用它,就会一直返回弱引用;否则,它将为空"。 - Ethan Wang
显示剩余8条评论

34

这两个定义不是完全相同的。

绝对不是。你指出的这两个定义中的关键区别在于“只要有其他人”。正是“其他人”非常重要。

考虑以下情况:

__strong id strongObject = <some_object>;
__weak id weakObject = strongObject;

现在我们有了一个强引用和一个弱引用指向<some_object>。如果我们像下面这样将strongObject设置为nil

strongObject = nil;

如果按照您提供的规则操作,您需要问自己以下问题:

  1. 强引用:将对象保存在堆中,直到不再指向它

    strongObject 不再指向 <some_object>,因此我们不需要保留它。

  2. 弱引用:只要有其他对象强引用它,就一直保存它

    weakObject 仍然指向 <some_object>,但由于没有其他对象指向它,这个规则也意味着我们不需要保留它。

结果是 <some_object> 被释放了,如果您的运行时支持它(Lion 和 iOS 5 及以上版本),那么 weakObject 将自动设置为 nil

现在考虑如果我们这样把 weakObject 设置为 nil 会发生什么:

weakObject = nil;

如果您按照您所概述的规则进行操作,那么您会问自己以下问题:

  1. 强引用:"在我不再指向它之前,将其保留在堆中"

    strongObject 确实指向 <some_object>。因此我们需要保留它。

  2. 弱引用:"只要有其他人强引用它,就将其保留"

    weakObject 不指向 <some_object>

结果是,<some_object> 没有被释放,但 weakObject 将成为 nil 指针。

[请注意,这一切都是基于假设 <some_object> 没有被其他强引用或其他方式所持有]


1
因此,强引用和弱引用的主要区别在于,指向强引用的对象的释放将自动将所有相关的弱引用指针设置为nil。对于一个弱引用指向的东西,总是存在一个强引用指针。如果是这样,那么主应用程序对象必须被强引用指向吗? - KMC
对于弱指针要指向有效的内容,必须有一个强指针。加上iOS 5和Lion支持弱引用的自动置空,你就得到了你所说的东西。但是iOS 4的运行时不支持这一点。我猜您所说的“主应用程序对象”是指UIApplication对象?那将被UIKit的内部机制强引用 - 但您不需要担心这个。 - mattjgalloway
我认为你可以使用像“strongObjectPointer”这样的词,而不是“strongObject”。这样编程新手就能更好地理解。对@BJ Homer帖子的发现很不错,Matt先生很有趣 :) - Vijay-Apple-Dev.blogspot.com

3

Strong

  1. 创建属性和分配值之间的所有权关系。
  2. 在ARC中,这是对象属性的默认设置,因此它不会让您担心引用计数并自动释放引用。
  3. 它是retain的替代品。我们仅在需要使用retain时才使用它。

Weak

  1. 创建属性和分配值之间的非所有权关系。
  2. 当强引用父对象时,弱引用子对象,当父对象被释放时,则将子对象引用设置为nil。
  3. 它有助于防止保留循环。
  4. 它不会在垃圾收集器收集引用对象时保护引用对象。
  5. Weak本质上是一个分配但不保留的属性。

值得在此提及的是保留周期的典型定义。我们有两个对象:对象A和对象B。对象A对对象B有一个强引用,而对象B对对象A也有一个强引用。除此之外,没有其他对象对对象A或B有强引用。 - boro

2

另一个例子: 学生是一个对象,假设她/他只要完成所有的核心课程(强指针)就能毕业(释放内存),无论是否选择选修课程(弱指针)。换句话说:强指针是该对象释放内存的唯一因素。


1
我知道我来晚了,但是我认为指出“强内存模型和弱内存模型”的含义取决于你是否在讨论软件或硬件问题是很重要的。
对于硬件而言,“弱”或“强”意味着它是否支持顺序一致性。
【SC表示】...任何执行的结果都与所有处理器的操作以某种顺序执行的结果相同,并且每个单独处理器的操作按其程序中指定的顺序在该序列中出现。 - Lamport, 1979 这与内存有什么关系?它意味着不同处理器对变量的写入必须由所有处理器以相同的顺序看到。在具有强模型的硬件上,可以保证这一点。但在具有弱模型的硬件上,则不能。
现有的答案只从软件内存模型的角度解释了这个问题。硬件对编程也是有影响的。这个问题提到了 iOS,它通常运行在 Arm7 处理器上。Arm7 有一个弱内存模型。对于习惯于具有强模型的处理器的程序员来说 - 因为 x86 和 x64 都有强模型 - 这是一个可怕的陷阱。在强模型中使用 bool 来向另一个线程发出退出信号是可以正常工作的。在 Arm 上,相同的代码根本不起作用,除非你将标志标记为 volatile,即使这样,它也是不稳定的。
虽然 Arm8+ 明确支持获取/释放,但遗留软件并没有使用此支持。遗留软件包括所有三个手机操作系统及其上运行的所有内容,以及编译器和库,直到它们得到更新为止。
关于这个主题的进一步研究,我建议您参考无与伦比的 Herb Sutter 的 文章

1
不,它们并不相同,而是非常不同的。只有在需要保留对象时才使用 strong。在任何其他情况下都使用 weak,因为这样可以知道对象是否已从堆中删除,因为没有人保留它的优点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接