Iphone 为属性分配内存时可能发生泄漏

Iphone 为属性分配内存时可能发生泄漏,iphone,ios,button,memory-management,retain,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行分配变量的潜在泄漏,即:;自选

我在研究内存管理时,发现了这个

我创建了一个属性按钮

@property (nonatomic, retain) UIButton *button;
在ViewdidLoad方法中,我编写了以下代码

self.button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
[self.view addsubView:self.button];
在进行XCode分析时,我得到了第33行分配变量的潜在泄漏,即:;自选按钮

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

谢谢
Jithen

将值分配给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];


将值分配给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];

@property(非原子,保留)UIButton*按钮使用此选项可以保留对象

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

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

Abstract

使用factory方法或使用alloc、new、retain、copy、mutableCopy创建对象时,对象每次都有+1个retain count。在这种情况下,您拥有对象。你有责任发布它。所以,在使用完对象后,您需要释放对象,这会导致-1 retain count保留对象

编辑

现在你在做什么

@property (nonatomic, assign) UIButton *button;
self.button = [[UIButton alloc] init];
[self.button release];
在这里,您使用self访问对象,self调用您创建的属性的变量。您将在属性对象上发送+1 retain count,使其变为2,因为它本身具有getter和setter属性。因此,您可以像这样使用实例变量,而不是这样做

@property (nonatomic, assign) UIButton *button;
_button = [[UIButton alloc] init];
[_button release];
@property(非原子,保留)UIButton*按钮使用此选项可以保留对象

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

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

Abstract

使用factory方法或使用alloc、new、retain、copy、mutableCopy创建对象时,对象每次都有+1个retain count。在这种情况下,您拥有对象。你有责任发布它。所以,在使用完对象后,您需要释放对象,这会导致-1 retain count保留对象

编辑

现在你在做什么

@property (nonatomic, assign) UIButton *button;
self.button = [[UIButton alloc] init];
[self.button release];
在这里,您使用self访问对象,self调用您创建的属性的变量。您将在属性对象上发送+1 retain count,使其变为2,因为它本身具有getter和setter属性。因此,您可以像这样使用实例变量,而不是这样做

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

在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];
第二个示例说明,您实际上不需要让属性保留按钮(通过
retain
strong
),因为将子视图添加到视图容器时,包含的视图将保留新的子视图

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

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


更新:我想在这里评论一下,这种问题就是苹果希望人们使用ARC的原因。这是一个非常基本的内存管理场景,它将继续挫败许多新开发人员。在这一点上,没有什么理由让iOS开发者开始使用ARC。

在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];
第二个示例说明,您实际上不需要让属性保留按钮(通过
retain
strong
),因为将子视图添加到视图容器时,包含的视图将保留新的子视图

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

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

更新:我想在这里评论一下,这种问题就是苹果希望人们使用ARC的原因。这是一个非常基本的内存管理场景,它将继续挫败许多新开发人员。在这一点上,有非常重要的意义