Iphone 我应该在哪里调用[对象释放]?

Iphone 我应该在哪里调用[对象释放]?,iphone,memory-management,Iphone,Memory Management,我对一些UITextField进行了子类化,并添加了一些自定义属性 在UITableViewController中,我在ViewDiDLoad中初始化它们,在cellForRowAtIndexPath中,我使用[cell.contentView addSubview:customTextField]将它们添加到单元格中 每个单元格都有一个不同的customTextField,因为它们都非常不同 我应该在哪里调用[customTextField release] 在我将它们添加到单元视图之后 例如

我对一些UITextField进行了子类化,并添加了一些自定义属性

在UITableViewController中,我在ViewDiDLoad中初始化它们,在cellForRowAtIndexPath中,我使用[cell.contentView addSubview:customTextField]将它们添加到单元格中

每个单元格都有一个不同的customTextField,因为它们都非常不同

我应该在哪里调用[customTextField release]

在我将它们添加到单元视图之后

例如,如果我调用[self.tableView reloadData],我的customTextField将被再次添加到单元格中,那么我是否应该改变这样做的方法

谢谢你的介绍

问候,


r、

我总是在使用addSubView将控件添加到视图后直接释放控件。当我使用表时,我也在CellForRowatineXpath方法中初始化它们


因此,对象在最短的时间内保持活动状态。

当您对对象不再感兴趣时,您可以
释放该对象。这有很多原因;这可能是因为您已经完成了对象,或者已经将对象生存期的控制权传递给了另一个对象。这可能是因为您将要用新实例替换对象,也可能是因为您(所有者对象)即将死亡

最后一个似乎与你的情况有关。您可以在
viewDidLoad
中创建这些对象,并反复使用它们(即将它们添加到单元格),直到对象不再运行为止。在这种情况下,正如您在
viewDidLoad
中创建它们一样,您可以在
viewDidUnload
中释放它们

编辑:我真的应该提到
自动释放
,但这与本例无关。内存管理最好用“所有者”的概念来处理——创建(或保留)某个东西的人应该负责删除它(或者用ObjC的说法是
release
ing)
autorelease
处理某些情况,在这些情况下,您需要将一个对象交给一个以前自己拥有它的备用所有者(通常通过返回方法)。如果您是创建者,您不能在将其返回给新所有者之前发布它,因为它将在新所有者有机会对其感兴趣之前被删除。然而,你不能只是不发布它;它会漏的。因此,系统提供了一个庞大的对象列表,它将在将来的某个时候代表您发布这些对象。您将您的
release
职责传递给此列表,然后
将对象返回给新所有者。此列表(自动释放池)确保您的释放将在某个时刻发生,但让新所有者有机会在对象被释放之前将其声明为自己的对象


在您的情况下,您显然有兴趣在视图控制器的生命周期内拥有这些对象—您需要随时能够将它们添加到视图单元以响应表数据重新加载。只有当视图控制器死亡时,才可以使用它们,因此
viewDidUnload
(或者可能
dealloc
)是
释放它们的唯一合理位置。

处理对象所有权的最安全方法是在初始化后直接自动释放视图:

FooTextField* textField = [[[FooTextField alloc] init] autorelease];
[myCell.contentView addSubview:textField];
将文本字段添加到superview(UITableViewCell
的contentView)会保留它。这样,您就不必关心以后是否发布视图


在iPhone开发者社区中,似乎存在着对自动释放的不满。在我看来,这种怨恨是没有根据的。如果对象的寿命比当前通过运行循环的时间长,则自动释放对象只会给程序增加很少的开销。

您不应该在cellForRowAtIndexPath中添加子视图!当每次显示单元时添加子视图时,这将减慢视图的速度。为此,请尝试使用自定义UITableViewCell类

这是UITableView定制的完美解决方案
工作正常

Obj-C中的每个对象都有一个引用计数器(重新计数),当该计数器变为0时,对象被释放。当您分配和初始化一个对象时,引用计数被设置为1-但是您可以保留它任意次数

UITextField *textField = [[UITextField alloc] init]; // Reference counter = 1
[textField retain]; // Reference counter = 2
[textField retain]; // Reference counter = 3
retain的反面是release,它从参考计数器中减去

...
[textField release]; // Reference counter = 2
[textField release]; // Reference counter = 1
您可以随时获取对象的参考计数器

printf("Retain count: %i", [textField retainCount]);

UIView
的方法
addSubview
确实
retain
您传入的子视图,当它完成时,它会释放它。如果以后需要在另一个作用域中使用
UITextField
(当
UIView
完成并已发布时)-将其添加到超级视图后,不应
发布它。大多数情况下,您实际上不需要保留引用,因此您应该在将其添加到超级视图后释放它。如果你没有-你可以
在你的范围内用dealloc方法发布它。

亚当·赖特很好地解释了这个理论,但让我给你一些实践。你对这个问题想得太多了,这几乎总是导致错误。有一个简单的解决方案几乎每次都能解决这个问题:使用访问器保留所有IVAR;不要保留非IVAR

.h

@interface ... {
    UITextField *_customTextField;
}
.m

@property (nonatomic, readwrite, retain) UITextField *customTextField;
...
@synthesize customTextField=_customTextField;

-(void)viewDiDLoad {
    self.customTextField = [[[UITextField alloc] init....] autorelease];
}
...
- (void)dealloc {
   // I do not recommend accessors in dealloc; but everywhere else I do
   [_customTextField release]; _customTextField = nil;
}

永远不要直接访问IVAR,除非是在
dealloc
中(即使这样也是有争议的,有些人建议
self.customTextField=nil;
dealloc
中;两种方式都有争议)。但不要直接分配IVAR。如果遵循此规则,您会发现大部分内存问题都会消失。

请查看UITableView-dequeueReusableCellWithIdentifier:和-initWithStyle:reuseIdentifier:

在-tableView:cellforrowatinexpath:中,使用-dequeueReusableCellWithIdentifier:并检查结果是否为零。如果是,则使用-initWithStyle:reuseIdentifier:实例化一个新单元格