iOS tableView中的MVC、MVVM
先貼上一張MVC的一張大圖(給自己看就好)

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中直接的設定。所以這次我的設定資料來源的方法圖片如下:

以往在設計一個tableView中有兩種以上不同cell時候,我容易在cellForRowAtIndexPath:這個方法中作出許許多多的if-else的判斷,而現在我將這個判斷交由cell自己來做,controller自己不需要知道cell是要什麼型別,而只要將得到的cell展示即可。
我們需要做的,就是傳入需要的資料,可以indexPath也可以是model等。這可能也很好的貫徹了“依賴注入”的設計原則。
同時,這可能對於後面的關於:自定義行高,一個tableView中有兩個cell等提供有益的幫助。
不過白貓黑貓,能抓到老鼠的的都是好貓哈哈哈。
補充:注意一定要傳入tableView,因為cell的複用問題。
2.tableView與自定義cell
這部分寫給自己看哈哈哈,主要是遇到了幾個忘記的知識點。
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
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,把功能實現就好,而從來沒有想過將程式碼寫在哪裡會更加合理。 當然上面的方法並不是最佳:joy:,自我總結,僅供參考,大神路過有意見,還望指點下。
本來還想通過嘗試tableView自動算高來鞏固複習tableView,然而發現這裡是一塊肥肉,考慮篇幅,還得重新開一篇筆記細細評味:joy:。