什么时候是reloadData的合适时机

时间:2010-10-31 02:11:19

标签: iphone objective-c

我有一个DetailsViewController类和一个ItemsViewController类。 (两者都来自UITableViewController)

选择ItemsViewController中的任何项目都会显示DetailsViewController。为了让它显示除第一个之外的任何新数据,我目前有

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [[self navigationItem] setTitle:title];
    [[self tableView] reloadData];
}

这个有效,但感觉就好像用大锤杀死一只苍蝇。什么是更好的方法呢?

提前致谢,

艾伦

5 个答案:

答案 0 :(得分:1)

结合以下几条评论中的想法:

BOOL needReload
作为成员变量添加到Details Controller。

然后在细节控制器中:

- (void)setData:(DataClass *)value {
     if (value == data)  
         return;
     id pointer = data;  
     data = [value retain];
     [pointer release];      // release after retain 
     needReload = TRUE;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    if(needReload){
       [[self navigationItem] setTitle:title];
       [[self tableView] reloadData];
       needReload = FALSE;
    }
}

答案 1 :(得分:0)

如果您知道只有特定的行或部分会发生变化,您可以指示烘焙视图仅重新加载那些行或部分。除此之外,-reloadData是大多数表视图的方式。

答案 2 :(得分:0)

我假设详细信息表中的项目会根据项目表中的所选项目而更改。所以,是的,这应该没问题。

除此之外,您可以检查上次是否选择了相同的项目,并且在此情况下不会调用reloadData。

答案 3 :(得分:0)

艾伦,

你的声明“为了让它显示除第一个之外的任何新数据”让我感到担忧 - 因为它告诉我你可能只有一个DetailsViewController实例。

在第一个表视图ItemsViewController中,您可能使用didSelectRowAtIndexPath:方法将DetailsViewController推送到UINavigationController堆栈。

我如何解决这个问题只是每当我的用户点击视图时创建/销毁一个新的DetailsViewController。所以,我的didSelectRowAtIndexPath:通常看起来像:

- (void) didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
  NSInteger selectedRow = indexPath.row;

  // Create a new view controller
  DetailsViewController *tmpVC = [[DetailsViewController alloc] initWithNibName:@"foo" bundle:nil];

  // Tell our new view controller what data it should be using
  tmpVC.tableData = [self.someArrayOfData objectAtIndex:selectedRow];

  // Push view controller and release it
  [self.navigationController pushViewController:tmpVC animated:YES];
  [tmpVC release];
}

此示例假设您拥有ItemsViewController中两个视图控制器所需的所有数据 - 可能不是这种情况..?

无论如何,通过这种方式,您的DetailsViewController会自动加载数据。当您点击“返回”返回到ItemsViewController时,UINavigationController将释放它,并将其销毁。然后,当用户点击不同的单元格时,我们再次运行此代码,创建一个全新的数据控制器 - 所以当它显示时,它会自动加载数据 - 它从未显示过。

您可能在代码中执行的操作是将DetailsViewController保留为ItemsViewController类的属性,然后重用该对象。如果您关心分配(例如,如果它是一个非常“重”的分配来构建DetailsViewController),这也可以工作,但是我认为调用reloadData的最佳位置不在类本身内 - 但是而是来自ItemsViewController的didSelectRowAtIndexPath:方法。

我推广创建/销毁方法而不是“flyweight模式”方法的原因是它使代码更加分离 - 视图控制器之间的链接越少越好。当然,ItemsViewController将始终依赖并了解DetailsViewController,但它不一定必须反过来 - 如果将reloadData调用添加到viewWillAppear:animated:,则隐式添加非代码两者之间的依赖关系。你知道当ItemsViewController是导航堆栈中的“父”时,这是正确的行为 - 但是如果你突然开始在应用程序的其他部分重用那个不需要重新加载的视图呢?这是一个性能受到打击,而且,它是一种隐藏的依赖关系,有一天可能最终会出现一个令人讨厌的错误。因此,如果确实需要只有1个DetailsViewController(而不是每次重新创建它的第一个想法),那么我将保持Details愚蠢并使Items包含所有复杂性。

答案 4 :(得分:0)

我建议将reloadData和setTitle放在viewDidLoad和setter中 - 我假设你在DetailsViewController中设置一个属性来改变表的数据源。所以viewDidLoad重新加载并设置标题,如果设置了属性,则setter重新加载并设置标题,如果isViewLoaded并且新值与旧值不同。

- (void)setSmth:(SmthClass *)value {
     if (value == smth)  // if they are the same and SmthClass is immutable,
                         // otherwise use isEqual and [self.tableView reloadData]
                         // before returning...
         return;
     id pointer = smth;  // if it's a retain property
     smth = [value retain];
     [pointer release];      // release after retain just to be extra safe

     if ([self isViewLoaded]) { 
          [self.tableView reloadData];
          [self setTitle:title];
     }
}

- (void)viewDidLoad {
     if (smth) {
         [self.tableView reloadData]; // maybe redundant...
         [self setTitle:title];
     }
}

或者您可以使用键值观察(NSKeyValueObserving协议)来观察您的属性并通知reloadData ...