0

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

我创建了一个属性按钮。

@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 或任何属性变量,它就会泄漏。

谢谢吉腾

4

5 回答 5

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)]; 
于 2013-04-11T04:49:35.120 回答
2

@property (nonatomic, retain) UIButton *button;使用它,您将保留对象。

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

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

摘要

当您使用工厂方法或使用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];
于 2013-04-11T04:49:52.837 回答
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 对象是有效的。不过,通常情况下,这不是必需的。

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

于 2013-04-11T04:50:09.463 回答
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,您的编码会简单得多。

于 2013-04-11T04:51:52.370 回答
0

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

-(void)dealloc {
    [button release];
    [super dealloc];
}
于 2013-04-11T04:54:41.323 回答