開頭:最近在利用有道的api嘗試做一個翻譯的應用,其中用到了tableview。有一段時間沒有接觸這個常用UI,發現該忘的都忘了哈哈。
本文不著重講述tableView的各種基本使用了,而打算通過下面幾個方面來進行敘述思考。在複習tableView的同時,想思考一下程式碼的規範問題。
- 1.tableView下中MVC思考
- 2.tableView與自定義cell
- 3.一個tableView,多種型別cell(MVVM模式)
1.tableView中MVC思考
先貼上一張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
這部分寫給自己看哈哈哈,主要是遇到了幾個忘記的知識點。
- 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,然而發現這裡是一塊肥肉,考慮篇幅,還得重新開一篇筆記細細評味?。