TextFieldDelegate过早被释放

时间:2010-10-12 14:37:56

标签: iphone objective-c memory-management

我的程序崩溃了,因为我的TextField在代理被释放后向其委托发送消息。我有一个对象,作为UITableViewDataSource和UITextFieldDelegate。在cellForRowAtIndexPath中,我在每个TableViewCell中创建一个TextField,并将self指定为TextField的委托。当我单击屏幕上的一个按钮时,视图会重新加载(它运行的是第一次加载视图时运行的所有相同代码):

DetailsViewController *controller = [[DetailsViewController alloc] initWithNibName:@"ClientView" bundle:nil];
self.detailsViewController = controller;
[controller release];

NRFCAppDelegate *appDelegate = UIApplication.sharedApplication.delegate;
for (UIView *view in [[[appDelegate.splitViewController.viewControllers objectAtIndex:1] view] subviews])
{
    [view removeFromSuperview];
}
CGRect rect = [[[appDelegate.splitViewController.viewControllers objectAtIndex:1] view] frame];
self.detailsViewController.view.frame = CGRectMake(0, 0, rect.size.width, rect.size.height);
[[[appDelegate.splitViewController.viewControllers objectAtIndex:1] view] addSubview:self.detailsViewController.view];

self.detailsViewController.detailsTitle.title = self.currentClient.name;
self.menuViewController.clientLabel.text = self.currentClient.name;

self.menuViewController.propertyLabel.text = @"Properties:";
self.menuViewController.addPropertyButton.hidden = NO;
self.menuViewController.editPropertiesButton.hidden = NO;

ClientMenuDelegate *menuDelegate = [[ClientMenuDelegate alloc] initWithRootController:self];
menuDelegate.properties = self.currentClient.properties.allObjects;
self.menuViewController.tableView.delegate = self.menuViewController.tableView.dataSource = menuDelegate;
self.menuViewController.delegate = menuDelegate;
[menuDelegate release];

ClientDetailsDelegate *detailsDelegate = [[ClientDetailsDelegate alloc] initWithRootController:self];
detailsDelegate.client = self.currentClient;
self.detailsViewController.tableView.delegate = self.detailsViewController.tableView.dataSource = detailsDelegate;
self.detailsViewController.detailsDelegate = detailsDelegate;
[detailsDelegate release];  

[self.menuViewController.tableView reloadData];
[self.detailsViewController.tableView reloadData];

self.detailsViewController.detailsDelegate = detailsDelegate;导致先前的ClientDetailsDelegate被释放(因此被释放),因为它是一个retain-type属性。问题是,如果我的TextField在单击重新加载按钮时是FirstResponder,它仍然会将它的textFieldShouldEndEditing,textFieldEditorDidChangeSelection等消息发送到现在解除分配的ClientDetailsDelegate。看起来这些消息应该在执行上述任何代码之前发送,因为TextField在单击按钮时失去焦点。此外,一旦调用了removeFromSuperview,TextField本身就不再存在了。

如何在重新加载视图时确保TextField被销毁,并在委托被解除分配后阻止它向其委托发送消息?

1 个答案:

答案 0 :(得分:0)

文本字段仅在所有这些内容发生后才发送这些消息,因为当前控件可能拒绝接受第一响应者。无论如何,原因并不重要。关键是你在使用它的控件完成之前就要销毁一个委托。行前:

self.detailsViewController.detailsDelegate = detailsDelegate;

您需要将旧委托所使用的控件的delegate属性设置为nil。您可以在委托对象的dealloc方法中执行此操作。


另一方面说明:

ClientMenuDelegate *menuDelegate = [[ClientMenuDelegate alloc] initWithRootController:self];
menuDelegate.properties = self.currentClient.properties.allObjects;
self.menuViewController.tableView.delegate = self.menuViewController.tableView.dataSource = menuDelegate;
self.menuViewController.delegate = menuDelegate;
[menuDelegate release];

看起来不对。您为menuDelegate指定的属性都不是保留属性。我认为一旦你释放它就会消失,留下悬空指针(除非menuViewController是你自己的类,你已经保留了委托属性)。