2010-07-16 84 views
17

我seeen下面的代码片段颇有几分:alloc + init与合成属性 - 是否会导致保留计数增加2?

在标题:

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]; 

Pr我的初步假设是正确的 - 我有兴趣知道是否有“正确”的方式来做到这一点,即属性的声明,初始化和内存管理?

+0

首先,欢迎使用Stack Overflow。在Stack上做的重要事情之一就是接受适合你的答案。这对回答者和你自己的声誉非常重要。 – smathy 2012-06-22 20:47:07

回答

8

是的,你是对的 - 使用retain属性的合成设置器会增加你已经拥有的实例的ref-count(因为alloc意味着所有权)。

与您在初始化中提到的第二种形式只是去:

_bla = [[SomeClass alloc] init]; 

...并记住否则修复保留计数,如:

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

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

是的。

我很想听听是否有“正确”的方式做到这一点

你的最后一段代码是正确的做法,但不建议前导下划线。该财产和伊娃可以共享相同的名称。只是

@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

+0

Wao - 我在stackoverflow上的第一篇文章,以及5分钟内的两个答案。谢谢你们俩! – patschiboy 2010-07-16 07:04:47

+6

你强烈劝阻的两种模式在大多数情况下是完全可以接受的,并且是正常的。您链接的答案只涉及**使用访问器在'init'和'dealloc'方法中设置对象。在其他地方,Apple建议始终使用访问器来访问实例变量。 – JeremyP 2010-07-16 08:17:21

+0

JeremyP是对的,因此这不应该被认为是一个正确的答案。 – Felixyz 2010-07-17 01:14:01

3

看起来这里的核心问题是Cocoa中对象所有权语义的误解。对于每个调用init,copyretain的对象,必须调用releaseautorelease。这里发生的是拨打initreleaseautorelease没有匹配的呼叫。

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

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

是不一样的东西:

bla = [[SomeClass alloc] init]; 

前者翻译成:

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

而后者则是名副其实的分配。

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

-3

没有重复计数。通过综合创建的制定者在进行保留​​之前进行发布。请参阅苹果网站上引用的斯坦福大学目标C类3课程。值得注意的是,在iboutlet的情况下,不需要alloc init,因为它通过加载xib文件来执行。

+0

投票失败。 [[xxx alloc] init]返回保留计数为1的对象,必须在某个时间点抵消该对象。如果将结果存储在保留属性中,则立即将保留属性设置为零,则会发生内存泄漏。 – gnasher729 2014-03-14 11:16:33