如果我有这样的属性,那么分配第一模式和第二模式的属性值有什么区别?
@interface Prueba : NSObject{
CustomeClass *_cclass;
}
@property(nonatomic, retain)CustomeClass *cclass;
@end
@implementation Prueba
@synthesize cclass = _cclass
- (void)config{
// 1 This
self.cclass = [[CustomeClass alloc] init];
// 2 This or
CustomeClass *cc = [[CustomeClass alloc] init];
self.cclass = cc;
[cc release];
}
@end
:/
答案 0 :(得分:0)
除了在第二种方法中创建一个额外的指针之外,结果没有区别。在两个版本self.cclass
中都可以保持您的对象。
问题在于,当您仅在第二种模式下释放对象时,在第一种模式下,您将发生内存泄漏。由于对象的retainCount
在分配时为+1,因此您可以通过setter分配+1对象。这意味着,您实际上再次提升了retainCount
。现在,如果你在将对象分配给你的属性后没有释放它,那么一旦它从那里被释放,retainCount
将只减少1.因此,让一个retainCount
为+1的对象浮动在记忆中,永远失去了。
但是因为您已经在询问更好的版本,我想向您介绍延迟实例化。你可以做的是,你覆盖有问题的属性的getter方法,并检查它是否已经分配。如果没有,则在getter方法中分配它,然后返回它。它看起来像这样:
- (CustomeClass*) cclass
{
if(!_cclass)
{
_cclass = [[CustomeClass alloc] init];
}
return _cclass;
}
使用此方法,您可以将+1保留对象分配给内部变量,从而绕过设置器而不增加retainCount
。此外,它还具有内存友好性,因为您只需在实际需要时对象进行实例化。现在,当您将属性设置为nil或某个新对象时,旧对象将被正确释放。
编辑:
在回应Robert Ryan的评论时,我想补充以下内容:
这不会破坏KVO,也不会干扰指定的属性资格。如果您的属性标记为assign
或weak
,那么延迟实例化并不真正有意义。如果它被标记为retain
或strong
这种实例化对象的方式非常好,特别是当它是你在配置方法中分配的属性时。
关于KVO:在getter中分配的值可以看作是初始/默认值,因此KVO仍然有效。当您使用setter为属性分配其他内容时,它将触发。您不希望KVO因为默认值而触发,是吗?
答案 1 :(得分:0)
您的第一个示例为您提供了一个保留计数为2(错误)的对象,而您的第二个示例为您提供了一个保留计数为1(右)的对象。第二种方法在非ARC项目中是首选。或者,您也可以自己设置ivar(我不喜欢,因为您没有使用setter):
_cclass = [[CustomeClass alloc] init];
或者使用setter作为你的例子,但是做一个自动释放(我不喜欢,因为你不应该推迟你的发布,除非你必须):
self.cclass = [[[CustomeClass alloc] init] autorelease];
在你的非ARC项目中,你原来的第二个例子是最好的(使用指针,使用你的属性的setter,然后释放你的指针),因为对于KVO你想养成使用setter的习惯:
CustomeClass *cc = [[CustomeClass alloc] init];
self.cclass = cc;
[cc release];