2010-10-31 49 views
0

我有一个DetailsViewController类和一个ItemsViewController类。 (都源自UITableViewController)什么时候是reloadData的合适时间

选择ItemsViewController中的任何项目都会调出DetailsViewController。为了得到它显示在任何新的数据,但第一位的,我现在有

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

工作,但感觉就像杀死一只苍蝇用大锤。什么是更好这样做的方法?

由于提前,

艾伦

+0

从什么是上面这个代码段? ItemsView或DetailsView ...你说他们都是桌子。 – 2010-10-31 05:05:41

+0

对不起,我应该提到。这是来自DetailsView。 – Alan 2010-11-01 10:46:32

回答

1

从一些意见在这里结合的想法变量到Details控制器。

然后在细节控制器:

 
- (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; 
    } 
} 
0

如果您知道,只有特定的行或部分将被改变,你可以直接烘烤,以便重新加载只有那些行或部分。除此之外,-reloadData是大多数表视图的方式。

0

我假设细节表上的项目根据项目表上的选定项目而变化。所以,是的,这应该没问题。

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

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(而不是每次重新创建它的第一个想法),我会保持细节愚蠢并使项目包含所有复杂性。

+0

你对我所做的事情的假设完全正确。我需要更多地考虑分配和取消分配detailsview的相关成本。嗯.. – Alan 2010-11-01 10:45:55

+0

你的数据有多大?通常项目中有多少行?详情中有多少数据? – makdad 2010-11-01 12:16:23

0

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

添加

BOOL needReload
作为成员:

- (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 ...

+0

这不会减少reloadData被调用的次数,并且会增加额外的开销。但我认为这是解决方案的一部分(特别是与下面的Altealice结合) – Alan 2010-11-01 10:48:30

+0

另外,viewDidLoad在每次显示控制器时都不会被调用。 – Alan 2010-11-01 10:52:58

相关问题