2014-12-19 34 views
2

當您使用委託和數據源創建表視圖時,您可以調用reloadData來強制它轉到數據源並獲取數據並顯示它。什麼觸發了UITableView第一次加載它的數據?

但是,您不需要首次執行此操作。首先使用它的數據源並開始加載數據的鉤子是什麼?

在UIView上沒有viewDidAppear或類似的東西。它不能被初始化,因爲它還沒有數據源。

我想創建我自己的控件,以類似的方式工作,我試圖找到一種方法,我可以用來觸發第一次調用數據源。

+4

在'numberOfSections'方法設置一個斷點,看看是什麼在呼喚它。 – rmaddy 2014-12-19 00:34:29

+1

我的猜測是,它的setDatasource方法一旦有非零數據源就立即啓動該進程。 – pbasdf 2014-12-19 00:42:12

+0

@pbasdf不需要,直到表格視圖即將顯示。 – rmaddy 2014-12-19 01:02:23

回答

3

我想您的自定義表類最好的解決辦法是: 1)必須在你有數據源,而不是重新加載willMoveToSuperview檢查類

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

2)內部的狀態isReloading:

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

上的setDataSource檢查3)如果有上海華不重裝:

- (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)有狀態的,你有數據源,而不是重新加載willMoveToSuperview檢查類

- (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)內isReloading:

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

3)在setDataSource上檢查是否有超級視圖而不重裝:

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

... 

reloadData將被稱爲畢竟這些線路已經執行,並且dataSource/delegate設置正確。

這可能不是UIKit正在做的事情,但它是否值得複製確切的機制?

+0

使用'dispatch_after'是一個非常糟糕的方法。你不能假定所有的東西都將被設置,並且在調用'init'的同一個runloop中作爲子視圖添加。這在你的例子中,但這是一個不好的假設。 – rmaddy 2014-12-19 01:05:33

0

好吧,等@rmaddy說過設置一個斷點(這是顯而易見的),我把一個放入numberOfSection dataSource方法。

堆棧跟蹤顯示,這從[UIView didMoveToWindow]開始,我實際上已經在文檔中遇到並且被解僱。

它實際上似乎被分成方法(很「乾淨」),因爲它運行_updateRowData然後invalidateAllSections然後_updateNumSections然後調用該dataSource得到部分的數量。

感謝@rmaddy做這給了我更多的想法,對我自己的看法:d

相關問題