Почему UITableView делает так много вызовов своему делегату и источнику данных? - PullRequest
4 голосов
/ 17 декабря 2009

Кто-нибудь хочет пролить свет на то, почему UITableView делает столько повторных вызовов своему делегату и источнику данных, сколько он настраивает? Просто глядя на один, над которым я сейчас работаю, я вижу, что numberOfSectionsInTableView вызывается 3 раза, а затем viewForHeaderInSection циклически повторяется еще 3 раза для каждого раздела (у меня есть 2 раздела, итого 6 раз перед отображается в первый раз) ... все до того, как первый экран будет отображен.

Я понимаю, что API является частным , но мне интересно, может ли кто-нибудь предложить какое-то понимание этого шаблона проектирования и что может происходить за кулисами, чтобы я мог кое-что узнать о том, почему такое многократное повторение считается приемлемым (или даже выгодным) в этом случае ... или, более вероятно, как мне удалось запутаться, применяя его.

Редактировать: добавлены трассировки стека до первого отображения RootViewController tableView

Первый раз вызывая 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

2-й звонок:

#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

3-ий звонок:

#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

4-й звонок:

#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

5-й звонок:

#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

6-й звонок:

#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

Ответы [ 2 ]

1 голос
/ 17 декабря 2009

В моем коде numberOfSectionsInTableView вызывается только один раз, в ответ на reloadData вызов.

Вы можете установить точку останова в numberOfSectionsInTableView и посмотреть на стек вызовов, чтобы увидеть, как и почему он вызывается.

0 голосов
/ 07 февраля 2010

Одна из причин, по которой он их часто называет, заключается в том, что все может резко меняться каждый раз, когда появляется [... reloadData] или что-то в этом роде, поэтому он не может делать никаких предположений о том, что все так, как было в прошлый раз, когда вы звонили их. Это одна из причин того, что они делают большую часть из кеширования UITableViewCells в документах, например.

Вот класс, демонстрирующий это:

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

В моем viewDidLoad я вызываю метод с именем setDataSourceAndDelegate, который устанавливает один из трех классов в качестве свойств источника данных и делегата в табличном представлении.

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

У меня есть три различных объекта, которые я использую как DataSource и Delegate (вместе взятые), с абстрактным классом над ними:

WinnersViewDefaultDSD
WinnersViewHasLocationDSD
WinnersViewHasExampleDSD

(по понятным причинам я заменил фактическое имя класса на пример с примером).

Теперь эти классы возвращают очень разные вещи в табличное представление, и иногда, когда изменяется состояние моего приложения (например, вызвав CoreLocation или пользователь выбирает экземпляр примера класса, метод setDataSourceAndDelegate вызывается снова, и он можно изменить, какой объект это на лету.

Итак, причина того, что UITableView вызывает так много вещей в своем делегате и источнике данных так много раз, заключается в том, что он должен поддерживать разработчиков, которые делают подобные вещи с табличным представлением. Если бы определенные методы вызывались один раз, а затем предполагалось, что ответ остается неизменным, он не был бы таким гибким.

В любом случае, надеюсь, это полезный пример.

(о, и если кто-то собирается подражать этому, обратите внимание, что свойства делегата и источника данных в TableView являются копиями и не сохраняются, поэтому вам нужно сделать дополнительное сохранение для экземпляров классов DSD, или вы получите таинственный, но частый сбой.)

(Кроме того, мне нужно было переопределить viewDidAppear для различных подклассов DSD, и в итоге мне пришлось это сделать:)

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

(это бит взлома, который не позволяет мне отслеживать объект DSD в классе.)

...