UITableview delegate dataSource調用探究,datasourcedelegate

來源:互聯網
上載者:User

UITableview delegate dataSource調用探究,datasourcedelegate

UITableview是大家常用的UIKit組件之一,使用中我們最常遇到的就是對delegate和dataSource這兩個委託的使用。我們大多數人可能知道當reloadData這個方法被調用時,delegate和dataSource就會被回調,但是其中具體的細節,可能很多人不會去探究。
我最近有興趣來探討這個問題是因為我最近遇到過dataSource中有的方法被調用,但是有的方法沒有被調用的情況,同時你會發現當tableview被add到一個superView的時候,也會觸發了reloadData一樣的回調。那麼這兩個委託究竟是怎麼執行的呢?

  • 我們首先來看看蘋果文檔對reloadData的描述

    Call this method to reload all the data that is used to construct the table, including cells, section headers and footers, index arrays, and so on. For efficiency, the table view redisplays only those rows that are visible. It adjusts offsets if the table shrinks as a result of the reload. The table view’s delegate or data source calls this method when it wants the table view to completely reload its data. It should not be called in the methods that insert or delete rows, especially within an animation block implemented with calls to beginUpdates and endUpdates.

    大致的意思就是說reload這個方法是用來構建table的,包括cell、section,而且只會對可見的行進行重新的繪製,當tableview想要完整的載入資料時,delegate和data source會調用此方法。增加刪除行,尤其是需要block動畫的時候不用用它。
    從這裡只能看出個大概,並沒有解釋調用的原理。

  • 那麼讓我們先寫一個最基本的tableview實現,然後對delegate和data source的回調設定一下斷點看看。

- (void)viewDidLoad {    [super viewDidLoad];    UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];    tableView.delegate = self;    tableView.dataSource = self;    [self.view addSubview:tableView];//    [tableView reloadData];//    [tableView layoutSubviews];}-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    return 60;}-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{    return 1;}-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    return 20;}-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    static NSString *cellID = @"cellID";    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];    if(!cell){        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];    }    cell.textLabel.text = @"哈哈";    return cell;}

我們先對下面這四個方法設定一下斷點,然後觀察左邊的棧資訊。

首先被調用的是numberOfSectionsInTableView:


numberOfSectionsInTableView:調用棧資訊.png


我們可以看到從addSubview是如何一步步調用到numberOfSectionsInTableView:的。
好的,我們下一步看斷點斷到了tableView:numberOfRowsInSection:上。


tableView:numberOfRowsInSection:調用棧資訊.png


_rebuildGeometry這個私人方法之前都是一樣的,所以我這裡並沒有全截,可以看到_rebuildGeometry中不僅調用了_updateRowData,還調用了一個_updateContentSize,從這裡來獲得每個section的行數。
我們接著往下看,到了tableView:heightForRowAtIndexPath:


tableView:heightForRowAtIndexPath:調用棧資訊.png


這裡通過了一個block回調的方式擷取了各個row的高度,並決定了整個section的高度。
然後我們會發現,以上的幾個方法還會再被調用一遍:


numberOfSectionsInTableView:調用棧資訊2.png


但是棧資訊已經不一樣了,這次調用時由於tableview調用了layoutSubviews,而reloadData是layoutSubviews裡調用的一個方法,因為layoutSubviews也是個公有的方法,所以我們可以用它來觸發reloadData。
斷點繼續執行,就執行到了tableView: cellForRowAtIndexPath:,我們用它來擷取tableview每個row的cell。


tableView: cellForRowAtIndexPath:調用棧資訊.png


我們會發現tableView: cellForRowAtIndexPath:並不是靠_rebuildGeometry下面的方法來觸發,而只是靠layoutSubviews來觸發,如果layoutSubviews沒有執行成功,那麼就可能會遇到我之前遇到過的前幾個方法執行而tableView: cellForRowAtIndexPath:不執行的問題。

    • 多瞭解UIKit的棧資訊能夠幫我們瞭解蘋果啟動並執行機制和原理,從而幫我們解決一些看起來非常詭異的bug,多看看蘋果的私人方法也有助於我們養成良好的編程習慣,我們盡量模仿蘋果的代碼規範無論是對自己寫代碼看著舒服,還是對他人來讀我們寫的代碼都一件好事。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.