我正在深入研究内存管理,我发现了这一点。
我创建了一个属性按钮。
@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
答案 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];
第二个示例说明您实际上不需要让您的属性保留按钮(通过retain
或strong
),因为当您将子视图添加到视图容器时,包含的视图将留住新生儿。
当然,也有一些例外。有时,您可能实际上想要从超级视图中删除视图(按钮),但不要让它被释放,因为您稍后会将其添加回来。
因此,有时,保留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];
}