是什么触发UITableView第一次加载其数据?

时间:2014-12-19 00:26:18

标签: ios uitableview

当您使用委托和数据源创建表视图时,可以在其上调用reloadData以强制它转到数据源并获取数据并显示它。

但是,您不需要第一次这样做。它首先用于数据源并开始加载数据的钩子是什么?

在UIView上没有viewDidAppear或类似的东西。它不能是init,因为它还没有数据源。

我尝试创建自己的控件,以类似的方式工作,我试图找到一种方法,可以用来触发对数据源的第一次调用。

3 个答案:

答案 0 :(得分:3)

我认为您的自定义表类最佳解决方案将是: 1)在类中有状态isReloading

- (void)reloadData {
_reloading = YES;
// Do someting
_reloading = NO;
}

2)在willMoveToSuperview检查您是否有数据源而不是重新加载:

- (void)willMoveToSuperview:(UIView *)superview {
    if (self.dataSource && !self.isReloading) {
      [self reloadData];
    }
    [super willMoveToSuperview:superview];
}

3)在setDataSource上检查是否有superview而不是重新加载:

- (void)setDataSource:(id<YourProtocolDelegate>)dataSource {
  _dataSource = dataSource;
  if (self.superview && !self.isReloading) {
    [self reloadData];
  }
}

有关UITableView函数调用的信息:

对于故事板加载:

2014-12-19 02:46:42.264 TestObjectiveC[21574:1891199] initWithCoder:
2014-12-19 02:46:42.266 TestObjectiveC[21574:1891199] setNeedsLayout
2014-12-19 02:46:42.266 TestObjectiveC[21574:1891199] setNeedsDisplay
2014-12-19 02:46:42.269 TestObjectiveC[21574:1891199] awakeAfterUsingCoder:
2014-12-19 02:46:42.269 TestObjectiveC[21574:1891199] setDataSource:
2014-12-19 02:46:42.270 TestObjectiveC[21574:1891199] setDelegate:
2014-12-19 02:46:42.270 TestObjectiveC[21574:1891199] awakeFromNib
2014-12-19 02:46:42.271 TestObjectiveC[21574:1891199] setNeedsDisplay
2014-12-19 02:46:42.298 TestObjectiveC[21574:1891199] willMoveToSuperview:
2014-12-19 02:46:42.300 TestObjectiveC[21574:1891199] didMoveToSuperview
2014-12-19 02:46:42.304 TestObjectiveC[21574:1891199] willMoveToWindow:
2014-12-19 02:46:42.306 TestObjectiveC[21574:1891199] didMoveToWindow
2014-12-19 02:46:42.307 TestObjectiveC[21574:1891199] setNeedsLayout
2014-12-19 02:46:42.342 TestObjectiveC[21574:1891199] setNeedsLayout
2014-12-19 02:46:42.343 TestObjectiveC[21574:1891199] layoutSubviews
2014-12-19 02:46:42.344 TestObjectiveC[21574:1891199] setNeedsLayout
2014-12-19 02:46:42.345 TestObjectiveC[21574:1891199] reloadData
2014-12-19 02:46:42.348 TestObjectiveC[21574:1891199] layoutSubviews

回溯:

  * frame #0: 0x000621bc TestObjectiveC`-[CustomTableView reloadData](self=0x7a37c400, _cmd=0x01915284) + 28 at CustomTableView.m:15
    frame #1: 0x0112232e UIKit`-[UITableView _reloadDataIfNeeded] + 78
    frame #2: 0x01128317 UIKit`-[UITableView layoutSubviews] + 36
    frame #3: 0x000623d8 TestObjectiveC`-[CustomTableView layoutSubviews](self=0x7a37c400, _cmd=0x01915520) + 120 at CustomTableView.m:34
    frame #4: 0x0109ddd1 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 608
    frame #5: 0x0055d771 libobjc.A.dylib`-[NSObject performSelector:withObject:] + 70
    frame #6: 0x0463d28f QuartzCore`-[CALayer layoutSublayers] + 152
    frame #7: 0x04631115 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 397
    frame #8: 0x04630f70 QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 26
    frame #9: 0x0458f3c6 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 284
    frame #10: 0x0459078c QuartzCore`CA::Transaction::commit() + 392
    frame #11: 0x04656799 QuartzCore`+[CATransaction flush] + 52
    frame #12: 0x01010286 UIKit`-[UIApplication _reportMainSceneUpdateFinished:] + 39
    frame #13: 0x01011201 UIKit`-[UIApplication _runWithMainScene:transitionContext:completion:] + 3163

对于initWithFrame加载:

2014-12-19 02:47:55.601 TestObjectiveC[21806:1895258] initWithFrame:style:
2014-12-19 02:47:55.604 TestObjectiveC[21806:1895258] setNeedsLayout
2014-12-19 02:47:55.605 TestObjectiveC[21806:1895258] setNeedsDisplay
2014-12-19 02:47:55.606 TestObjectiveC[21806:1895258] setDelegate:
2014-12-19 02:47:55.607 TestObjectiveC[21806:1895258] setDataSource:
2014-12-19 02:47:55.608 TestObjectiveC[21806:1895258] willMoveToSuperview:
2014-12-19 02:47:55.610 TestObjectiveC[21806:1895258] didMoveToSuperview
2014-12-19 02:47:55.640 TestObjectiveC[21806:1895258] willMoveToWindow:
2014-12-19 02:47:55.641 TestObjectiveC[21806:1895258] didMoveToWindow
2014-12-19 02:47:55.642 TestObjectiveC[21806:1895258] setNeedsLayout
2014-12-19 02:47:55.680 TestObjectiveC[21806:1895258] setNeedsLayout
2014-12-19 02:47:55.683 TestObjectiveC[21806:1895258] layoutSubviews
2014-12-19 02:47:55.684 TestObjectiveC[21806:1895258] setNeedsLayout
2014-12-19 02:47:55.684 TestObjectiveC[21806:1895258] reloadData
2014-12-19 02:47:55.686 TestObjectiveC[21806:1895258] layoutSubviews

回溯:

* frame #0: 0x0008517c TestObjectiveC`-[CustomTableView reloadData](self=0x7ba7f400, _cmd=0x01939284) + 28 at CustomTableView.m:15
    frame #1: 0x0114632e UIKit`-[UITableView _reloadDataIfNeeded] + 78
    frame #2: 0x0114c317 UIKit`-[UITableView layoutSubviews] + 36
    frame #3: 0x00085398 TestObjectiveC`-[CustomTableView layoutSubviews](self=0x7ba7f400, _cmd=0x01939520) + 120 at CustomTableView.m:34
    frame #4: 0x010c1dd1 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 608
    frame #5: 0x00581771 libobjc.A.dylib`-[NSObject performSelector:withObject:] + 70
    frame #6: 0x0466128f QuartzCore`-[CALayer layoutSublayers] + 152
    frame #7: 0x04655115 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 397
    frame #8: 0x04654f70 QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 26
    frame #9: 0x045b33c6 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 284
    frame #10: 0x045b478c QuartzCore`CA::Transaction::commit() + 392
    frame #11: 0x0467a799 QuartzCore`+[CATransaction flush] + 52
    frame #12: 0x01034286 UIKit`-[UIApplication _reportMainSceneUpdateFinished:] + 39
    frame #13: 0x01035201 UIKit`-[UIApplication _runWithMainScene:transitionContext:completion:] + 3163
    frame #14: 0x0104d7d0 UIKit`__84-[UIApplication 

更新:更正确的代码

1)在类

中有状态isReloading
- (void)reloadData {
// More correct code, due that user can trigger reloadData multiple times, and you can reload it async. So in this case it never calls few times at the same time
if (self.isReloading) return;
_reloading = YES;
// Do someting
_reloading = NO;
}

2)在willMoveToSuperview检查您是否有数据源而不是重新加载:

- (void)willMoveToSuperview:(UIView *)superview {
    if (self.dataSource) {
      [self reloadData];
    }
    [super willMoveToSuperview:superview];
}

3)在setDataSource上检查是否有superview而不是重新加载:

- (void)setDataSource:(id<YourProtocolDelegate>)dataSource {
  _dataSource = dataSource;
  if (self.superview) {
    [self reloadData];
  }
}

答案 1 :(得分:0)

您可以在自定义视图的初始化程序

中使用此技巧
- (instancetype)init {
    ...
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self reloadData];        
    });
}

这将在当前运行循环结束时调用reloadData(不是立即)。因此,如果有人使用您的自定义视图并且具有类似的内容(可能在viewDidLoad

...

customView = [[CustomView alloc] init];
customView.dataSource = ...
customView.delegate = ...
[view addSubView:customView];

...

{/ 1>}在所有这些行被执行后被称为reloadData / dataSource已正确设置。

这可能不正是delegate正在做的事情,但复制确切的机制是否值得呢?

答案 2 :(得分:0)

好的,所以在@rmaddy说要设置一个断点(这显然是真的很明显)后,我把一个放入numberOfSection dataSource方法。

堆栈跟踪显示这是从[UIView didMoveToWindow]开始的,我实际上已经在文档中遇到并被解雇了。

它实际上似乎被拆分为方法(非常&#34;干净&#34;),因为它运行_updateRowData然后invalidateAllSections然后_updateNumSections然后调用dataSource获取部分数量。

谢谢@rmaddy这样做,给了我更多关于我自己观点的想法:D