将内存分配给属性时可能发生泄漏

时间:2013-04-11 04:43:32

标签: iphone ios button memory-management retain

我正在深入研究内存管理,我发现了这一点。

我创建了一个属性按钮。

@property (nonatomic, retain) UIButton *button;

在ViewdidLoad方法中,我编写了以下代码。

self.button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
[self.view addsubView:self.button];

进行XCode分析,我在第33行可能会泄漏分配的变量,即; self.button。

为什么会这样?如果我创建一个本地UIButton并将其分配给self.button并使用它,那么就没有潜在的泄漏。如果我将内存分配给self.button或任何属性变量,它就会泄漏。

由于 Jithen

5 个答案:

答案 0 :(得分:2)

为self.button赋值会调用合成的setter方法:

- (void)setButton:(UIButton *)button;

因为您在属性声明中添加了“retain”属性,所以合成的setter会自动在设置的对象上调用“retain”。这会增加对象的保留计数。

在UIButton上调用“alloc”也会提升对象的保留计数。

所以做self.button = [UIButton alloc]基本上会使你的保留计数增加2.这就是潜在泄漏的原因。

您可以通过执行以下操作来解决此问题:

self.button = [[[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)] autorelease];

UIButton *temp = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
self.button = temp;
[temp release];

_button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)]; 

答案 1 :(得分:2)

@property (nonatomic, retain) UIButton *button;使用这个你保留对象。

现在使用self.button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];分配内存,保留计数增加1.

所以在你的情况下,这是一个泄漏,因为对象的保留计数增加了。如果您有本地对象并且您分配然后再次释放它。所以没有额外的保留计数,也没有泄漏。

Abstarct

当您使用工厂方法或使用 alloc,new,retain,copy,mutableCopy 创建对象时,您的对象每次都有 +1保留计数。在这种情况下你拥有对象。你有责任释放它。因此,在完成使用导致 -1保留计数对象的对象后,您需要释放对象。

修改

现在你正在做

@property (nonatomic, assign) UIButton *button;
self.button = [[UIButton alloc] init];
[self.button release];

在这里,您使用self访问对象,该对象调用您创建的属性的变量。您正在向属性对象发送+1保留计数,因此它将变为2作为其自身具有getter和setter的属性。因此,您可以像这样使用实例变量,而不是这样做。

@property (nonatomic, assign) UIButton *button;
_button = [[UIButton alloc] init];
[_button release];

答案 2 :(得分:1)

在ARC之前,您通常会为retain变量执行此操作:

UIButton* btn = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
self.button = btn;    // property increases retain count because of its declaration as "retain"
[btn release];

使用ARC,您可能会这样做:

@property (nonatomic, weak) UIButton* button;

self.button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
[self.view addsubView:self.button];

第二个示例说明您实际上不需要让您的属性保留按钮(通过retainstrong),因为当您将子视图添加到视图容器时,包含的视图将留住新生儿。

当然,也有一些例外。有时,您可能实际上想要从超级视图中删除视图(按钮),但不要让它被释放,因为您稍后会将其添加回来。

因此,有时,保留UI对象是有效的。通常情况下,没有必要。

更新:我想在此发表评论,这种问题是Apple希望人们使用ARC的原因。这是一个非常基本的内存管理方案,它继续阻碍很多新的开发人员。在这一点上,没有理由让iOS开发人员使用ARC。

答案 3 :(得分:1)

您的UIButton个实例被保留了两次。 [UIButton alloc]创建一个保留的实例,button属性在通过self.button分配时保留该属性。使用MRC(手动参考计数)代码,您需要释放您保留的任何内容。

创建按钮时,请执行以下操作:

UIButton *button = [[[UIButton alloc] initWithFrame:...] autorelease];
self.button = button;

或者,使用'UIButton'的首选创建者方法:

self.button [UIButton buttonWithType:UIButtonTypeCustom];
self.button.frame = CGRectMake(...);

您还需要在清理分配给您的属性的对象的任何位置释放按钮。如果使用ARC(自动参考计数)而不是MRC,那么编码将更加简单。

答案 4 :(得分:0)

我不知道你是否已经发布它,但每当我们分配内存时,我们必须释放它(如果你的项目中没有使用ARC)。 所以只需在dealloc中释放它:

-(void)dealloc {
    [button release];
    [super dealloc];
}