具有综合属性的 alloc + init - 是不是会导致保留计数增加 2?

Posted

技术标签:

【中文标题】具有综合属性的 alloc + init - 是不是会导致保留计数增加 2?【英文标题】:alloc + init with synthesized property - does it cause retain count to increase by two?具有综合属性的 alloc + init - 是否会导致保留计数增加 2? 【发布时间】:2011-03-16 19:25:40 【问题描述】:

下面的sn-p我看过不少:

在标题中:

SomeClass *bla;
@property(nonatomic,retain) SomeClass *bla;

在实现文件中:

@synthesize bla;

然后

self.bla = [[SomeClass alloc] init];

我认为这个分配将 'bla' 的保留计数增加了 2;一次通过 alloc/init 调用,然后通过我们要求通过综合属性设置器发生的保留。

因此,我通常这样声明我的属性:

在标题中:

SomeClass *_bla; // note the underscore
@property(nonatomic,retain) SomeClass *bla;

在实现文件中:

@synthesize bla = _bla;

然后

_bla = [[SomeClass alloc] init];

如果我最初的假设是正确的 - 我很想知道是否有“正确”的方法来做到这一点,即属性的声明、初始化和内存管理?

【问题讨论】:

首先,欢迎来到 Stack Overflow。在 Stack 上要做的重要一件事就是接受对你有用的答案。这对回答者很重要,对您自己的声誉也很重要。 【参考方案1】:

是的,您是对的 - 使用 retain 属性的综合设置器会增加您已经拥有的实例的引用计数(因为 alloc 意味着所有权)。

只需使用您在初始化程序中提到的第二种形式:

_bla = [[SomeClass alloc] init];

...并记住要修复保留计数,例如:

self.bla = [[[SomeClass alloc] init] autorelease];

【讨论】:

【参考方案2】:

我认为这个分配将 'bla' 的保留计数增加了 2;

是的。

我很想知道是否有“正确”的方法来做到这一点

您的最后一段代码是正确的方式,但不建议使用前导下划线。属性和 ivar 可以共享相同的名称。只是

@interface Foo : Bar 
  SomeClass* bla;

@property (nonatomic, retain) SomeClass* bla;
@end

@implementation Foo
@synthesize bla;
-(id)init 
   ...
   bla = [[SomeClass alloc] init];
   ...

-(void)dealloc 
  [bla release];
  ...
  [super dealloc];

够了。


有些人可能会使用

SomeClass* foo = [[SomeClass alloc] init];
self.bla = foo;
[foo release];

self.bla = [[[SomeClass alloc] init] autorelease];

-init 方法中,但我强烈反对它,因为这会不必要地调用许多方法 and you cannot guarantee the behavior of the setter。

【讨论】:

Wao - 我在 *** 上的第一篇文章,5 分钟内有两个答案。谢谢你们! 您强烈反对的两种模式在大多数情况下是完全可以接受和正常的。您链接到的答案与使用访问器在initdealloc 方法中设置对象有关。在其他任何地方,Apple 建议始终使用访问器来访问实例变量。 JeremyP 是对的,因此不应将其视为正确答案。 应该被严重否决推荐没有前导下划线的实例变量。具有相同的属性标识符和实例变量将不可避免地导致混乱和严重的错误。就像意外分配给 bla 而不是 self.bla 时不正确的保留计数、未触发观察者等等。【参考方案3】:

看起来这里的核心问题是对 Cocoa 中对象所有权语义的误解。对于每个在对象上调用的initcopyretain,都必须调用releaseautorelease。这里发生的是对init 的调用没有对releaseautorelease 的匹配调用。

我认为这里令人困惑的是属性分配的点符号是方法调用的语法糖。所以看起来它只是一个赋值,而实际上它是对属性设置器的调用。

self.bla = [[SomeClass alloc] init];

与以下内容不同:

bla = [[SomeClass alloc] init];

前者翻译成:

[self setBla: [[SomeClass] alloc] init]];

而后者实际上是一项任务。

要解决您的问题,您真正需要做的就是确保调用init 的代码调用autorelease,以便在setter 调用retain 之后减少保留计数。

【讨论】:

【参考方案4】:

没有重复计数。由 synthesize 创建的 setter 在执行保留之前执行释放。请参阅苹果网站上引用的关于目标 c 类 3 的斯坦福课程。还值得注意的是,如果是 iboutlets,则不需要 alloc init,因为它是通过加载 xib 文件来执行的

【讨论】:

因错误而被否决。 [[xxx alloc] init] 返回一个保留计数为 1 的对象,该对象必须在某个时候被抵消。如果将结果存储在保留属性中,然后立即将保留属性设置为 nil,则会发生内存泄漏。

以上是关于具有综合属性的 alloc + init - 是不是会导致保留计数增加 2?的主要内容,如果未能解决你的问题,请参考以下文章

目标 C,iOS:不在子视图上调用 alloc 或 init

new和alloc init的区别

选择了具有“保留(或强)”属性的属性进行综合

使用alloc后如何初始化UIButton的类型?

cdev_alloc() 与 cdev_init()

OC知识点alloc 和init