在ARC中,当你不合成时会发生什么?

8
在启用了iOS ARC的项目中,如果我不合成一个属性,由于禁止保留/释放,会发生什么?
@interface SomeClass : NSObject {
    NSMutableArray*     _pieces;
}
@end

在这种情况下,iVar _pieces的内存语义是什么? 如果我使用_pieces = whatever进行设置,那么_piecesset是否为nil? _piecesset是否存储为弱引用? 如果所有其他对象都释放了对_pieces的保留,当我尝试访问它时,它会变成null吗?

4
为什么这个被标记了,它看起来是一个非常有效有用的问题。 - 1dayitwillmake
5个回答

16

以下是一些观察,其中许多可能已经基于他人的反馈而变得清晰明了:

  1. 你需要合成属性,而不是实例变量。在你的例子中,你展示了一个实例变量的例子,而不是属性。

  2. 你的问题可能意味着在合成和能够执行 retain/release 之间存在某种假定的联系,但实际上并没有这样的联系。能否执行 retainrelease 取决于你是否使用 ARC。它与合成属性无关。

  3. 正如其他人所观察到的那样,明确声明的实例变量(例如你的例子)默认情况下是 strong 引用。因此,在你的例子中,_pieces 是一个 strong 引用。

  4. 当你的 SomeClass 对象被释放时,它将删除对 _pieces 对象的引用。显然,如果这是指向由 _pieces 指向的对象的最后一个强引用,则该对象将被释放,你在其他地方可能有的任何 weak 引用将被设置为 nil。有关内存管理的更完整讨论,请参见 Apple 的 Advanced Memory Management Programming GuideTransitioning to ARC

  5. 你问道“如果所有其他已经对 _pieces 保留的对象都释放它了,我尝试访问它时它会是 nil 吗?”显然,如果 _pieces 是一个 weak 引用,那么这将是正确的,但是鉴于它在 SomeClass 中是隐式的一个强引用,所以不,不是这样的情况。

  6. 如果你想把 pieces 做成 declared property,语法应该是:

    @property (nonatomic, strong) NSMutableArray* pieces;

    指定strong还是weak(或其他)取决于属性的内存管理。

  7. 如果你声明了一个属性,则你不再需要明确定义实例变量,而现在建议你确实不要这样做(因为当它被合成时,编译器将为你创建实例变量)。但是,如果你恰好有一个明确声明的与属性名称相同的实例变量,编译器将使用该变量作为属性。但这不仅是不必要的,而且是不可取的(因为如果你拼写实例变量的名称错误,可能会无意中得到两个实例变量)。让编译器为你的属性合成实例变量,这个潜在的歧义就消失了。

  8. 用于属性的实例变量的名称由 property implementation directive 的语法控制,即 @synthesize 语句。因此,如果你有一个形如

    @synthesize pieces;

    @synthesize 语句,则实例变量将被称为 pieces。但是,如果你使用首选的

    @synthesize pieces = _pieces;

    语法,则实例变量名称将带有前导下划线(根据惯例,这被认为是首选的,以避免在代码中出现属性和实例变量之间的歧义)。从 Xcode 4.4 开始,


假设 @synthesize 属性是用于公共变量,而 iVar 是用于类外部不需要关心的变量,这是否是一个好的假设? - 1dayitwillmake
@1dayitwillmake 你肯定想要在你的.h文件中声明公共属性以暴露数据(即你的“公共变量”)。个人而言,我将我的私有实例变量和属性放在.m文件中的私有类扩展中。 - Rob
@1dayitwillmake 无论私有数据是存储为ivars还是属性,都是个人偏好的问题(我通常使用ivars,但理解为什么人们使用私有属性,但我受到实用考虑的驱动,而不是宗教狂热)。此外,请注意您可以在.h文件中限制范围(例如使用@private指令),但我认为将私有内容放在类扩展中更加清晰。 - Rob

3
假设您没有创建使用此属性的属性,覆盖了默认行为,ARC项目中的实例变量被认为是强引用,因此声明实际上是:
@interface SomeClass : NSObject {
    __strong NSMutableArray* _pieces;
}
@end

所以,针对你的问题回答如下:

当我的SomeClass实例被释放时,_pieces是否置为nil?

不会,但将实例分配给它也不会导致其被释放。

_pieces是作为弱引用存储的吗?

不是,它是一个强引用。

如果所有其他保留了_pieces的对象都释放了它,那么当我尝试访问它时,它会变成null吗?

不会,这与您的第一个问题相同。


我该如何“释放”引用以允许其被解除分配。 - 1dayitwillmake
好的,改变 _pieces 所指向的对象。它是由变量引用的对象,当该变量被释放时,对象会跟踪引用它的内容(保留计数)。如果一个强引用变量引用了一个对象,则保留计数会增加。如果该对象不再被特定变量引用,则保留计数会减少。一旦保留计数为0,就可以将其释放。 - WDUK

2

你是在声明一个名为pieces的属性,还是直接使用了ivar?

如果你定义了一个属性,那么内存使用情况取决于你如何定义该属性。

如果这是一个直接的ivar,则默认情况下ivar将是strong。这基本上意味着ivar将正确地保留和释放你分配给它的任何对象。你可以放心使用它而不必担心。


0
据我所知,ARC 将会像strong一样对待它。当你给它赋值时,传入的值将被retain,而不再指向的值将被release。只有在某种情况下过度释放了它,它才会悬空。如果你有一个属性声明,ARC 将遵守其中指定的规则,并且访问器将以@synthesize someObject = _someObject的形式自动合成。当对象被释放时,我认为对象会被发送release,因此如果没有其他东西断言拥有权,则指针指向的对象也将被释放。

0

使用新的运行时,你只需要使用 @properties - 不要声明 ivars,也不要合成


这意味着他想要一个属性。拥有没有属性的ivar也完全没问题。 - rmaddy
1
如果我不进行综合处理,它会产生一个错误:自动属性综合处理正在综合处理未显式综合处理的属性。 - 1dayitwillmake

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