我是 iOS5 开发和使用 Objective-c 的新手。我很难理解强存储和弱存储之间的区别。我已阅读文档和其他 SO 问题,但它们听起来都与我相同,没有进一步的见解。
我阅读了 the documentation: Transitioning To ARC - 它引用了 iOS4 的保留、分配和释放条款;这让我很困惑。然后我研究了 Open U CS193p,它区分了强弱:
强:“将其保留在堆中,直到我不再指向它为止” 弱:“只要其他人强烈指向它,就保留它”
这两个定义不是相同的=如果指针不再指向一个对象,则释放保存该对象的内存吗?我理解指针、堆、内存分配或释放的概念——但是强弱之间有什么区别?
不同之处在于,一旦没有指向它的强指针,对象就会被释放。即使弱指针指向它,一旦最后一个强指针消失,对象将被释放,所有剩余的弱指针将被清零。
也许一个例子是为了。
想象我们的对象是一只狗,而这只狗想要逃跑(被释放)。
强指针就像狗的皮带。只要你把皮带拴在狗身上,狗就不会逃跑。如果五个人将他们的皮带拴在一只狗身上(五个强指针指向一个物体),那么在所有五根皮带都脱离之前,狗不会逃跑。
另一方面,弱指针就像小孩子指着狗说“看!一条狗!”只要狗还在皮带上,小孩子仍然可以看到狗,他们仍然会指向它。然而,一旦所有的皮带都松开了,不管有多少小孩指着它,狗都会跑掉。
一旦最后一个强指针(leash)不再指向一个对象,这个对象就会被释放,所有的弱指针都会被清零。
这两个定义不是相同的。
绝对不。您指出的两个定义的主要区别是“只要别人”。重要的是“别人”。
考虑以下:
__strong id strongObject = <some_object>;
__weak id weakObject = strongObject;
现在我们有两个指向 <some_object>
的指针,一个是强的,一个是弱的。如果我们像这样将 strongObject
设置为 nil
:
strongObject = nil;
然后,如果您仔细阅读您概述的规则,那么您会问自己以下问题:
强:“将其保留在堆中,直到我不再指向它为止” strongObject 不再指向
结果是 <some_object>
被解除分配,如果您的运行时支持它(Lion 和 iOS 5 以上),那么 weakObject
将自动设置为 nil
。
现在考虑如果我们像这样将 weakObject
设置为 nil
会发生什么:
weakObject = nil;
然后,如果您仔细阅读您概述的规则,那么您会问自己以下问题:
强:“将它保留在堆中,直到我不再指向它”strongObject 确实指向
结果是 <some_object>
没有被释放,但 weakObject
将是 nil
指针。
[请注意,所有假设 <some_object>
都没有被其他地方的另一个强引用/其他一些被“持有”的方式指向]
UIApplication
对象?这将被 UIKit
的内部工作强烈引用 - 但您不必担心这一点。
强的
在财产和分配的价值之间建立所有权。这是 ARC 中对象属性的默认设置,因此它不会让您担心引用计数并自动释放引用。它是保留的替代品。当且仅当我们需要用作保留时,我们才使用。
虚弱的
在财产和分配的价值之间创建非所有权。 Strong 用于父对象,weak 用于释放父对象时的子对象,然后子对象引用也设置为 nil 它有助于防止保留循环。垃圾收集器收集时它不保护引用的对象。弱本质上是分配的,不保留的财产。
另一个例子:学生是Object
,假设她/他只要完成所有核心课程(strong pointers
)就可以毕业(deallocate
),无论她/他是否参加选修课程( weak pointers
)。换句话说:强指针是释放 Object
的唯一因素。
不,它们并不相同,但非常不同。只有在需要保留对象时才使用 strong 。在任何其他情况下都使用弱,其优点是您可以知道对象是否已从堆中删除,因为没有人保留它。
我知道我参加这个聚会已经很晚了,但我认为通过指出“强和弱内存模型”的含义取决于您是在谈论软件还是硬件来混淆这个问题很重要。
对于硬件,weak 或 strong 表示是否支持顺序一致性。
[SC 意味着] ...任何执行的结果都与所有处理器的操作都按某种顺序执行的结果相同,并且每个单独的处理器的操作按照其程序指定的顺序出现在该顺序中。 - 兰波特,1979
WTF 这和内存有关系吗?这意味着所有处理器必须以相同的顺序查看不同处理器对变量的写入。在具有强大模型的硬件中,这是有保证的。在具有弱模型的硬件上,它不是。
现有答案仅根据软件内存模型解释该问题。硬件与编程并非无关。这个问题提到了 iOS,它通常在 Arm7 处理器上运行。 Arm7 的内存模型很弱。对于习惯于具有强大模型的处理器的程序员来说——这是我们所有人,因为 x86 和 x64 有一个强大的模型——这是一个可怕的陷阱。在强模型中,使用 bool 来指示另一个线程退出可以正常工作。除非您将标志标记为 volatile,否则 Arm 上的相同代码根本不起作用,即使那样它也是不稳定的。
虽然 Arm8+ 确实通过对获取/发布的明确支持彻底改变了这一点,但旧版软件不使用这种支持。旧版软件包括所有三个手机操作系统及其上运行的所有内容,以及编译器和库,直到它们被更新。
对于这个主题的扩展检查,我建议您参考无与伦比的 Herb Sutter。