iOS tableView中的MVC、MVVM

開頭:最近在利用有道的api嘗試作一個翻譯的應用,其中用到了tableview。有一段時間沒有接觸這個經常使用UI,發現該忘的都忘了哈哈。react

本文不着重講述tableView的各類基本使用了,而打算經過下面幾個方面來進行敘述思考。在複習tableView的同時,想思考一下代碼的規範問題。

  • 1.tableView下中MVC思考
  • 2.tableView與自定義cell
  • 3.一個tableView,多種類型cell(MVVM模式)

1.tableView中MVC思考

先貼上一張MVC的一張大圖(給本身看就好)api

mvc.jpeg
controller 至關於媒介,幫助model和View創建其聯繫。道理我都懂,可是以往在coding的時候,每每會出現如下的狀況(代碼不看):

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    TeacherHomeworkListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TeacherHomeworkListCell" forIndexPath:indexPath];
    cell.delegate = self;
    NSArray *arr = homeworkListModelTDArray[indexPath.section];
    cell.model = arr[indexPath.row];
    if ([cell.model.requirements isEqualToString:@"0"]) {
        cell.operateView.hidden = YES;
        cell.correctHomeworkButton.hidden = YES;
        cell.operateViewNR.hidden = NO;
    } else {
        cell.operateView.hidden = NO;
        
        .......
複製代碼

貼上這麼多之前的代碼主要的,是能夠看出在以往coding過程當中,我又容易忽視了mvc的設計思想。這可能會致使:緩存

  • 1.將view(cell)和model(數據)在controller中創建起了直接的聯繫。
  • 2.又會讓tableView顯得龐然大物。

所以在此次coding 的過程當中,我時不時有意地注意到了這個問題,將全部的與UI展現有關的數據交由View下來處理,而避免在controller中直接的設置。因此此次個人設置數據源的方法圖片以下:bash

以往在設計一個tableView中有兩種以上不一樣cell時候,我容易在cellForRowAtIndexPath:這個方法中做出許許多多的if-else的判斷,而如今我將這個判斷交由cell本身來作,controller本身不須要知道cell是要什麼類型,而只要將獲得的cell展現便可。mvc

咱們須要作的,就是傳入須要的數據,能夠indexPath也能夠是model等。 這可能也很好的貫徹了「依賴注入」的設計原則。mvvm

同時,這可能對於後面的關於:自定義行高,一個tableView中有兩個cell等提供有益的幫助。ide

不過白貓黑貓,能抓到老鼠的的都是好貓哈哈哈。ui

補充:注意必定要傳入tableView,由於cell的複用問題。


2.tableView與自定義cell

這部分寫給本身看哈哈哈,主要是遇到了幾個忘記的知識點。spa

  • 1.若是事先給tableView註冊了cell類型,則不須要進行cell爲空的處理,緩存池中就會有足夠的cell等待複用。
  • 2.在經過[_tableView registerClass...]註冊了cell以後,在進行cell複用時,底層是調用了 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier的方法,所以若是須要返回xib自定義的cell,則須要對這個方法override。
  • 3.在經過xib自定義時,須要經過tableViewDelegate設置行高(代理裏的默認行高爲44),不然可能沒法徹底展現xib的cell。
  • 4.經過xib加載cell時候,底層會調用awakeFromNib的方法(這個也忘了😂)

3.一個tableView,多種類型cell

在現現在的應用程序當中,一個tableView中含有多種類型的cell,這已經是一個廣泛的UI需求。翻譯

參考了網上各類方法以後,自我總結了一下。 我想到了以下兩種:

  • 1.將相關參數傳入view,經過view來返回須要指定類型的cell。
  • 2.根據兩種不一樣的標識符,獲取不一樣的cell。

對於第一種方法:

我在實現的過程當中,將view與xib綁定在一塊兒,根據傳入的indexPath或者數據,返回出指定類型的的cell。以往我會在xib文件中只放一個cell,而這次我則再也不是經過[array lastObject]取出惟一的cell,而是根據指定的index從多個cell中取出指定的cell。

附上僞碼:

@implementation CustomCell
- (instancetype)cellWithIndexPath:(NSIndexPath *)indexPath {
    CustomCell *cell = nil;
    NSArray *cellArr = [[NSBundle mainBundle] loadNibWith...];
    if (...){
        cell = [cellArr objectAtIndex:index];
    }else if (...) {
        ...
    }else {
        cell = [cellArr lastObject];
    }
    return cell;
}
@end
複製代碼

可是這種方法的缺點也很明顯,與tag的使用大同小異。當一個tableView須要許多種類型的cell來豐富內容的時候,採用這種方法在開發過程當中會帶來必定的混亂。

能夠適當的採用enum枚舉,但同時也要注意xib中左面板中視圖的上下位置。

例如上圖中,NormalTyepCell 的index=1,MeTypeCell爲2,而當二者調換了位置以後,索引也會發生改變。

對於第二種方法:

我的也比較傾向於第二種方法,對於不一樣的類型的cell,應有不一樣的Identifier進行綁定,這樣子比較科學哈哈,同時採用了較爲高大上的MVVM,。

咱們大能夠像第一種方式同樣,從xib中取出所須要的cell,可是這也許就沒有多個Identifier存在的必要性。而針對不一樣標識符取出對應的cell,更多的是依賴:

[tableView dequeueReusableCellWithIdentifier:Identifier]; 的調用。

如何得到對應cell的Identifier:

一樣是能夠採用前面的方法來進行開發,可是細想一下,若是cell的類型過多,這樣子會致使view中代碼成本太高,相比與第一種方法,這種方法則更加麻煩。

如何解決?那就着手已產生的麻煩---胖View。

MVVM

開始寫文章的時候並無考慮,可是寫着寫着就以爲也許能夠應用進來哈哈。9012但願能多寫文章,記錄筆記!

先貼幾張MVVM的大圖:

對於新面孔ViewModel:從MVC的controller中抽取出來的展現邏輯,負責從model中獲取view所需的數據,轉換成View能夠展現的數據,並暴露公開的屬性和命令供view進行綁定。

回到第二種方法的實現上來。

MVVM的採用能夠很好的爲view以及controller制定了瘦身的計劃,咱們將「獲取指定cell的Identifier」這一邏輯交由ViewModel來實現,而後經過controller告訴view須要哪一個cell。

附上viewModel和tableView設置數據源的僞碼:

@implementation ViewModel 
- (NSString *)identifierWith:(Model *)model {
    if (model.type == ?){
        return firstCellID;
    }else if (model ...){
        return secondCellID;
    }else {
        return ...
    }
}
@end

@implementation controller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *identifier = [_viewModel identifierWith:model];
    return [tableView dequeReusa....:identifier];
}
@end
複製代碼

在設置數據源方法中,我沒有進行cell爲空的操做處理,由於須要在這以前,對tableView進行全部類型cell的註冊,我的也比較喜歡先註冊cell的方式,這樣子可讓代碼看起來更加直觀。


結尾:

回顧前面所講的,個人出發點能夠理解爲始終是一個---爲controller制定瘦身計劃,同時使代碼更加容易維護。 以前只是一直想着coding,把功能實現就好,而歷來沒有想過將代碼寫在哪裏會更加合理。 固然上面的方法並非最佳😂,自我總結,僅供參考,大神路過有意見,還望指點下。

原本還想經過嘗試tableView自動算高來鞏固複習tableView,然而發現這裏是一塊肥肉,考慮篇幅,還得從新開一篇筆記細細評味😂。

參考

ReactiveCocoa and MVVM, an Introduction

相關文章
相關標籤/搜索