4

Anyone care to shed some light on why UITableView makes so many repeat calls to its delegate & datasource as it's being setup? Just looking at one I'm working on now I see that numberOfSectionsInTableView is called 3 times and then viewForHeaderInSection cycles through 3 more times for each section (I have 2 sections so total of 6 times before being displayed for first time)...all before the first screen is even rendered.

I realize that the API is private but wondering if someone might be willing to offer up some insight into this design pattern and what might be going on behind the scenes so I might learn a thing or two about why so much repetition is considered acceptable (or even advantageous) in this case...or, more likely, how I've managed to foul up applying it.

Edit: Added stack traces before RootViewController tableView is shown for first time

1st time calling viewForHeaderInSection:

#0  0x000086cc in -[RootViewController tableView:viewForHeaderInSection:] at RootViewController.m:444
#1  0x30c901a8 in -[UITableView(UITableViewInternal) _delegateWantsHeaderForSection:]
#2  0x30c8f6f4 in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:]
#3  0x30c8f5a8 in -[UITableViewRowData rectForFooterInSection:]
#4  0x30c3d430 in -[UITableViewRowData heightForTable]
#5  0x30c05430 in -[UITableView(_UITableViewPrivate) _updateContentSize]
#6  0x30c3ce0c in -[UITableView noteNumberOfRowsChanged]
#7  0x30c3c7c0 in -[UITableView reloadData]
#8  0x30e50e60 in -[UITableViewController viewWillAppear:]
#9  0x30c78810 in -[UINavigationController _startTransition:fromViewController:toViewController:]
#10 0x30c783b0 in -[UINavigationController _startDeferredTransitionIfNeeded]
#11 0x30c782a0 in -[UINavigationController viewWillLayoutSubviews]
#12 0x30c5c874 in -[UILayoutContainerView layoutSubviews]
#13 0x30c382d8 in -[UIView(CALayerDelegate) _layoutSublayersOfLayer:]
#14 0x33e871c0 in -[CALayer layoutSublayers]
#15 0x33e86edc in CALayerLayoutIfNeeded
#16 0x33e86844 in CA::Context::commit_transaction
#17 0x33e86474 in CA::Transaction::commit
#18 0x33e8e5dc in CA::Transaction::observer_callback
#19 0x32d5c830 in __CFRunLoopDoObservers
#20 0x32da4346 in CFRunLoopRunSpecific
#21 0x32da3c1e in CFRunLoopRunInMode
#22 0x31bb9374 in GSEventRunModal
#23 0x30bf3c30 in -[UIApplication _run]
#24 0x30bf2230 in UIApplicationMain
#25 0x00002260 in main at main.m:14

2nd call:

#0  0x000086cc in -[RootViewController tableView:viewForHeaderInSection:] at RootViewController.m:444
#1  0x30c901a8 in -[UITableView(UITableViewInternal) _delegateWantsHeaderForSection:]
#2  0x30c8f6f4 in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:]
#3  0x30c90628 in -[UITableViewRowData(UITableViewRowDataPrivate) _ensureSectionOffsetIsValidForSection:]
#4  0x30c8f5d0 in -[UITableViewRowData rectForFooterInSection:]
#5  0x30c3d430 in -[UITableViewRowData heightForTable]
#6  0x30c05430 in -[UITableView(_UITableViewPrivate) _updateContentSize]
#7  0x30c3ce0c in -[UITableView noteNumberOfRowsChanged]
#8  0x30c3c7c0 in -[UITableView reloadData]
#9  0x30e50e60 in -[UITableViewController viewWillAppear:]
#10 0x30c78810 in -[UINavigationController _startTransition:fromViewController:toViewController:]
#11 0x30c783b0 in -[UINavigationController _startDeferredTransitionIfNeeded]
#12 0x30c782a0 in -[UINavigationController viewWillLayoutSubviews]
#13 0x30c5c874 in -[UILayoutContainerView layoutSubviews]
#14 0x30c382d8 in -[UIView(CALayerDelegate) _layoutSublayersOfLayer:]
#15 0x33e871c0 in -[CALayer layoutSublayers]
#16 0x33e86edc in CALayerLayoutIfNeeded
#17 0x33e86844 in CA::Context::commit_transaction
#18 0x33e86474 in CA::Transaction::commit
#19 0x33e8e5dc in CA::Transaction::observer_callback
#20 0x32d5c830 in __CFRunLoopDoObservers
#21 0x32da4346 in CFRunLoopRunSpecific
#22 0x32da3c1e in CFRunLoopRunInMode
#23 0x31bb9374 in GSEventRunModal
#24 0x30bf3c30 in -[UIApplication _run]
#25 0x30bf2230 in UIApplicationMain
#26 0x00002260 in main at main.m:14

3rd call:

#0  0x000086cc in -[RootViewController tableView:viewForHeaderInSection:] at RootViewController.m:444
#1  0x30c901a8 in -[UITableView(UITableViewInternal) _delegateWantsHeaderForSection:]
#2  0x30c3eebc in -[UITableView(_UITableViewPrivate) _updateVisibleHeadersAndFootersNow]
#3  0x30c3e578 in -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow]
#4  0x30c3c514 in -[UITableView layoutSubviews]
#5  0x30c382d8 in -[UIView(CALayerDelegate) _layoutSublayersOfLayer:]
#6  0x33e871c0 in -[CALayer layoutSublayers]
#7  0x33e86edc in CALayerLayoutIfNeeded
#8  0x33e86844 in CA::Context::commit_transaction
#9  0x33e86474 in CA::Transaction::commit
#10 0x33e8e5dc in CA::Transaction::observer_callback
#11 0x32d5c830 in __CFRunLoopDoObservers
#12 0x32da4346 in CFRunLoopRunSpecific
#13 0x32da3c1e in CFRunLoopRunInMode
#14 0x31bb9374 in GSEventRunModal
#15 0x30bf3c30 in -[UIApplication _run]
#16 0x30bf2230 in UIApplicationMain
#17 0x00002260 in main at main.m:14

4th call:

#0  0x000086cc in -[RootViewController tableView:viewForHeaderInSection:] at RootViewController.m:444
#1  0x30c9712c in -[UITableView(UITableViewInternal) _sectionHeaderViewWithFrame:forSection:opaque:reuseViewIfPossible:]
#2  0x30c3f0b4 in -[UITableView(_UITableViewPrivate) _updateVisibleHeadersAndFootersNow]
#3  0x30c3e578 in -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow]
#4  0x30c3c514 in -[UITableView layoutSubviews]
#5  0x30c382d8 in -[UIView(CALayerDelegate) _layoutSublayersOfLayer:]
#6  0x33e871c0 in -[CALayer layoutSublayers]
#7  0x33e86edc in CALayerLayoutIfNeeded
#8  0x33e86844 in CA::Context::commit_transaction
#9  0x33e86474 in CA::Transaction::commit
#10 0x33e8e5dc in CA::Transaction::observer_callback
#11 0x32d5c830 in __CFRunLoopDoObservers
#12 0x32da4346 in CFRunLoopRunSpecific
#13 0x32da3c1e in CFRunLoopRunInMode
#14 0x31bb9374 in GSEventRunModal
#15 0x30bf3c30 in -[UIApplication _run]
#16 0x30bf2230 in UIApplicationMain
#17 0x00002260 in main at main.m:14

5th call:

#0  0x000086cc in -[RootViewController tableView:viewForHeaderInSection:] at RootViewController.m:444
#1  0x30c901a8 in -[UITableView(UITableViewInternal) _delegateWantsHeaderForSection:]
#2  0x30c3eebc in -[UITableView(_UITableViewPrivate) _updateVisibleHeadersAndFootersNow]
#3  0x30c3e578 in -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow]
#4  0x30c3c514 in -[UITableView layoutSubviews]
#5  0x30c382d8 in -[UIView(CALayerDelegate) _layoutSublayersOfLayer:]
#6  0x33e871c0 in -[CALayer layoutSublayers]
#7  0x33e86edc in CALayerLayoutIfNeeded
#8  0x33e86844 in CA::Context::commit_transaction
#9  0x33e86474 in CA::Transaction::commit
#10 0x33e8e5dc in CA::Transaction::observer_callback
#11 0x32d5c830 in __CFRunLoopDoObservers
#12 0x32da4346 in CFRunLoopRunSpecific
#13 0x32da3c1e in CFRunLoopRunInMode
#14 0x31bb9374 in GSEventRunModal
#15 0x30bf3c30 in -[UIApplication _run]
#16 0x30bf2230 in UIApplicationMain
#17 0x00002260 in main at main.m:14

6th call:

#0  0x000086cc in -[RootViewController tableView:viewForHeaderInSection:] at RootViewController.m:444
#1  0x30c9712c in -[UITableView(UITableViewInternal) _sectionHeaderViewWithFrame:forSection:opaque:reuseViewIfPossible:]
#2  0x30c3f0b4 in -[UITableView(_UITableViewPrivate) _updateVisibleHeadersAndFootersNow]
#3  0x30c3e578 in -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow]
#4  0x30c3c514 in -[UITableView layoutSubviews]
#5  0x30c382d8 in -[UIView(CALayerDelegate) _layoutSublayersOfLayer:]
#6  0x33e871c0 in -[CALayer layoutSublayers]
#7  0x33e86edc in CALayerLayoutIfNeeded
#8  0x33e86844 in CA::Context::commit_transaction
#9  0x33e86474 in CA::Transaction::commit
#10 0x33e8e5dc in CA::Transaction::observer_callback
#11 0x32d5c830 in __CFRunLoopDoObservers
#12 0x32da4346 in CFRunLoopRunSpecific
#13 0x32da3c1e in CFRunLoopRunInMode
#14 0x31bb9374 in GSEventRunModal
#15 0x30bf3c30 in -[UIApplication _run]
#16 0x30bf2230 in UIApplicationMain
#17 0x00002260 in main at main.m:14
4

2 回答 2

1

In my code numberOfSectionsInTableView is only called once, in response to a reloadData call.

You can set a breakpoint in numberOfSectionsInTableView and look at the call stack to see how and why it's being called.

于 2009-12-17T00:49:08.073 回答
0

它经常调用它们的原因之一是每次有 [... reloadData] 或其他任何东西时情况都会发生巨大变化,因此它不能假设事情与您上次调用它们时一样。UITableViewCells例如,这就是他们在文档中大量使用缓存的原因之一。

这是一个展示这一点的课程:

@interface WinnersViewController : UITableViewController {
}
- (void)setDataSourceAndDelegate;
@end

在我的 viewDidLoad 中,我调用了一个方法,该方法setDataSourceAndDelegate将三个类之一设置为表视图上的数据源和委托属性。

- (void)viewDidLoad {
    [self setDataSourceAndDelegate];
    [super viewDidLoad];
}

我有三个不同的对象,它们充当我使用的 DataSource 和 Delegate(组合),它们上面有一个抽象类:

获奖者查看默认DSD
优胜者ViewHasLocationDSD
优胜者ViewHasExampleDSD

(出于显而易见的原因,我已经用 Example 替换了实际的类名。)

现在这些类向表 View 返回非常不同的东西,有时当我的应用程序的状态发生变化时(比如调用 CoreLocation 或用户选择类示例的实例,该setDataSourceAndDelegate方法被再次调用,它可以改变它是哪个对象在飞行中。

所以,UITableView 在它的委托和数据源上调用这么多东西的原因是因为它需要支持开发人员用表格视图做这种事情。如果某些方法被调用一次,然后假设答案不变,它就不会那么灵活。

无论如何,希望这是一个有用的例子。

(哦,如果有人要效仿这一点,请注意 TableView 上的委托和数据源属性是复制而不是保留,因此您必须对 DSD 类的实例进行额外保留,否则您会得到一个神秘但经常崩溃。)

(另外,我需要覆盖各种 DSD 子类的 viewDidAppear 并最终需要这样做:)

- (void)viewDidAppear:(BOOL)animated
{
    [[(UITableView*)self.view delegate] delegatedViewDidAppear];
}

(这有点让我不必在课堂上跟踪 DSD 对象。)

于 2010-02-06T22:48:49.200 回答