【问题标题】:Why does an empty tableView check the number of sections but a non-empty one does not?为什么一个空的 tableView 会检查节的数量而非空的不检查?
【发布时间】:2012-09-09 00:34:55
【问题描述】:

我用一个简单的UITableViewController 设置了一个演示应用程序,没有任何内容,但工具栏中有一个“添加”按钮。这将启动一个模态视图控制器,除了“取消”按钮之外,它又是空的。取消按钮只是告诉它的delegateUITableViewController)关闭模式。

然后我在UITableViewControllernumberOfSectionsInTableView 方法中添加了一个NSLog 语句。

通常,当表视图控制器加载时,我会看到两个对numberOfSectionsInTableView 的调用。当我打开并关闭模式(返回到UITableViewController)时,我看不到对numberOfSectionsInTableView 的进一步调用。

但是,如果我从 numberOfSectionsInTableView 返回 0,除了显示的两个调用之外,我还会在模态关闭时看到一个额外的 numberOfSections 调用。

这仅在numberOfSectionsInTableView 返回0 时发生,并且除了提到的之外,我没有向我的项目添加任何其他代码。正如我所描述的那样,通过设置几个控制器并修改来自numberOfSectionsInTableView 的结果,这很容易验证。

我的问题:

  • 为什么UITableView 在从模态视图返回时调用numberOfSectionsInTableView
  • 为什么只有在numberOfSectionsInTableView返回0时才这样做?
  • 除了numberOfSectionsInTableViewUITableViewController 在模态关闭时也会调用cellForRowAtIndex:。实际上,它正在尝试显示其dataSource 的新内容。如果添加的第一行已经自动更新,我该如何手动为行插入设置动画?难道不应该让我来确保我的UITableView 与其dataSource 一致吗?
  • UITableViewController 检查什么属性以知道有一个或多个部分(因此询问我的代表有多少部分)?它不能是 numberOfSectionsInTableView 本身,因为每当我从模式返回时,我都会看到它被调用,而不仅仅是在 numberOfSections = 0 时。

【问题讨论】:

  • 你能发布示例代码吗?另外我不明白你的第三和第四个问题,你能改写一下,也许提供更多的上下文?您在讨论中根本没有涉及动画。
  • 我已经添加了一个演示,很快也会添加代码。我还将尝试澄清我的补充观点。感谢您清理我草率的问题。
  • 代码有点长,所以我链接到我的演示项目。我还试图尽我所能澄清我的问题。我不是在寻求有关动画的建议,只是指出 tableview 将在显示时自动刷新(仅限第一行)我将没有机会自己插入行。

标签: objective-c ios uitableview


【解决方案1】:

来自UITableViewController docs:

当表格视图第一次加载时即将出现时, 表视图控制器重新加载表视图的数据... UITableViewController 类在超类方法中实现了这个 viewWillAppear:

如果您在调试器中观看,应用启动时的第二次调用来自UITableViewControllerviewWillAppear: 实现 - 特别是上面提到的部分,其中tableView 发送@ 987654328@留言。

现在,启动时对numberOfSectionsInTableView:第一次调用也来自UITableViewControllerviewWillAppear: 实现,但不是直接来自该实现对-[UITableView reloadData] 的调用。我不确定第一个电话是关于什么的。

但是,对于您的问题,在解除模式时发生的对numberOfSectionsInTableView: 的调用与来自applicationDidFinishLaunching:withOptions:第二个 调用具有完全相同的调用堆栈。然后我的假设是UITableView 将零部分解释为处于根本没有加载的状态。这确实有些道理。我认为“空”表视图是一个没有任何,但没有任何部分 的表视图对我来说几乎是“未初始化”的。此外,UITableViewDataSource 文档暗示UITableView 默认有一节。从此方法返回零也与文档的假设不一致。

现在,对于您对动画的关注 - 如果您给表格一个空白部分来使用,您将能够完全控制插入第一行的任何动画,而不会被锁定在当你需要重新加载时。

我认为这个故事的寓意是,不要返回零部分,除非你真的、真的需要出于某种原因。您帖子的标题也提到了这个表格视图是“空的”,但我认为很明显框架发现零部分不是空的而是卸载的。

希望这会有所帮助!感谢您发布示例项目供我使用。

【讨论】:

  • 这是一个很好的答案,非常感谢。有两件事让我在这里绊倒。首先,Xcode 生成的 UITableViewController 子类返回 0,我认为这是一个合理的默认值(或至少占位符)。其次,我正在填充数组中的部分数,因此返回array.count。我想我只需要返回 MAX (1, array.count)。我很惊讶我无法在其他地方找到对此的其他引用——也许从数组中填充部分并不常见。再次感谢您的彻底回答。
  • 给其他人的一些额外提示 - 如果你实现 titleForHeaderInSection 或任何其他与节相关的委托,这些都必须更新以在你的节数据源为空的特殊情况下返回 nil。否则将显示第一节的页眉、页脚等而不是空列表,即使没有行。
  • 不客气!是的,这个模板有一些奇怪的地方——...cellForRow... 存根也忽略了实例化单元格。很好地抓住了部分标题方法。框架和文档中似乎存在一些关于空表应该如何工作的紧张关系。
【解决方案2】:

也许代表简直不敢相信自己的眼睛。但说真的,由于表格视图必须至少有一个部分,因此传递 0 没有任何意义。为什么这样做?你传给它一个无效的参数,它会给你一个奇怪的响应。至于为什么当你通过 1 时它不询问部分的数量,我认为这是因为它不需要知道此时(从模态视图控制器返回)——表格视图已经被填充(如果有一些数据)并且您没有更改模型中的任何内容,因此不需要更新。

我在您的示例项目中添加了几行,以便您每次从模态视图控制器返回时连续滑动,这就是我认为您正在尝试做的事情。我为 numberOfRowsInSection 的返回值添加了一个 int 属性 num,添加了一个数组来填充表格,并从模态视图控制器解除方法调用了 insertRowsAtIndexPaths。

- (void)viewDidLoad
{
    _num = 0;
    self.theData = @[@"one",@"two",@"three"];
    [super viewDidLoad];
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
                                                                                          target:self
                                                                                          action:@selector(addRecipe)];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    NSLog(@"# sections requested");
    //when 0, this fires on return from the modal. When 1, it does not.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSLog(@"in numberOfRows in section");
    return _num;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"in cellForRowAtIndexPath");
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil];
    cell.textLabel.text = [self.theData objectAtIndex:indexPath.row];
    return cell;
}

- (void)addRecipe
{
    //create the modal and suscribe for delegate notifications
    AddRecipeViewController *addRecipeController = [[AddRecipeViewController alloc]initWithStyle:UITableViewStyleGrouped];
    addRecipeController.delegate = self;

    //display the modal in a navigation controller
    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:addRecipeController];
    [self.navigationController presentModalViewController:navController animated:YES];
}

- (void)addRecipeVC:(AddRecipeViewController *)addRecipeVC didAddRecipe:(NSString *)recipe
{
    [self dismissModalViewControllerAnimated:YES];
    _num += 1;
    [self performSelector:@selector(addRow) withObject:nil afterDelay:.5];
}

-(void)addRow {
    [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:_num-1 inSection:0]] withRowAnimation:UITableViewRowAnimationRight];
}

【讨论】:

    【解决方案3】:

    表格视图在用数据填充表格视图时检查部分的数量!
    由于表格可以分为多个部分,因此它必须具体知道将其分为多少个部分。

    重新加载数据时,还会检查节数。

    因为每次表格视图必须采取行动来访问表格的数据时,例如您点击了哪一行,在哪个部分,或者填充数据表,必须知道部分的数量!


    希望这有帮助!

    【讨论】:

    • 很遗憾没有 - 我知道这种行为。我试图找出为什么一个空的 tableview 会自动检查显示的部分的数量,但一个有 1 行或更多行的却不会。不过还是谢谢。
    猜你喜欢
    • 2019-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多