MVVM在Swift中的應用(利用TableView實現)

為了好看隨便放張圖XD

前言

在OC中成熟的框架已經有很多了,但是Swift一直找不到..可能是我檢索能力不強,希望大家能推薦給我,我只在viewModel中抽象了幾個常用的方法,如果需要可以自己在里面擴展
文章里還講了一點AutoLayout計算cell高度的方法

上代碼

ViewModel

主要是把tableView的Delegate和DataSource拆分出來,利用Block讓ViewController可以生成cell,和處理點擊事件

import UIKit

typealias ZECellRenderBlock = (indexPath:NSIndexPath,tablleView:UITableView) -> UITableViewCell!
typealias ZECellSelectBlock = (indexPath:NSIndexPath,tablleView:UITableView) -> Void

class ZETableViewModel: NSObject,UITableViewDelegate,UITableViewDataSource {
    
    var cellRender:ZECellRenderBlock! // 創建cell的block
    var cellSlect:ZECellSelectBlock? // 選中cell的block
    var cellHeight:CGFloat = UITableViewAutomaticDimension
    var estimatedHeight:CGFloat = 50// 預估高度
    var sectionCount:Int = 0// 區數
    var rawCount:Int = 0// 行數
    
    /** 區數 */
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return sectionCount
    }
    /** 行數 */
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return rawCount
    }
    /** 行高 */
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return cellHeight
    }
    /** cell */
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = cellRender(indexPath: indexPath,tablleView: tableView)
        return cell
    }
    /** 預估高度 */
    func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return estimatedHeight
    }
    /** 點擊事件 */
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        guard let selectBlock = cellSlect else{
            print("cell的選中block沒有實例")
            return
        }
        selectBlock(indexPath:indexPath,tablleView:tableView)
    }
}

Model

我一般喜歡把model當做controller的垃圾桶,把所有非View方法都封裝到model中,這里寫了一個模擬網絡請求的方法

import UIKit
typealias ModelBlock = (success:Bool,status:String) -> Void
class ZEVCModel: NSObject {
    
    var dataArr:Array<ZESomeData> = []

    func getData(block:ModelBlock){
        for dic in self.someData{
            
            let title = dic["bigTitle"]
            let context = dic["context"]
            let model = ZESomeData(bigTitle:title, context: context)
            dataArr.append(model)
        }
        block(success: true, status: "獲取數據成功")
    }
    
    var someData = [
        [
            "bigTitle":"我是大標題",
            "context":"我是一個超長超長超長超長超長超長超長超長超長超長超長超長超長超長的內容"
        ]
    ]
}

View

這里僅用一個Cell來表示View,可以講一下通過AutoLayout自動計算cell高度的方法,就是所有控件都給好高度,需要變換高度的給一個帶優先級的高度約束,然后在tableview中這樣設置(已demo為例),一定要有預估高度和UITableViewAutomaticDimension

    var cellHeight:CGFloat = UITableViewAutomaticDimension // cell高
    var estimatedHeight:CGFloat = 50// 預估高度
/** 行高 */
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return cellHeight
    }
/** 預估高度 */
    func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return estimatedHeight
    }

貼一下約束圖,如果兩個label都會變換高度的話 可以改優先級,點Height Equals的Edit就可以設置優先級了

大標題的高度固定為25

詳情Label的高度>=20,優先級為1000

Controller

controller中只用關注model什么時候獲取數據,創建什么樣的cell,什么時候刷新界面,點擊時怎么處理就好了

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var tableView: UITableView!
    let viewModel = ZETableViewModel()
    let model = ZEVCModel()
    override func viewDidLoad() {
        super.viewDidLoad()
        self.automaticallyAdjustsScrollViewInsets = false
        layoutSomething()
    }
    /**
     加載ViewModel,Model 刷新數據
     */
    func layoutSomething(){
        tableView.delegate = viewModel
        tableView.dataSource = viewModel
        viewModel.sectionCount = 1
        viewModel.cellHeight = UITableViewAutomaticDimension
        tableView.registerNib(UINib.init(nibName: "ZECell", bundle: nil), forCellReuseIdentifier: "ZECell")
        weak var weakSelf = self
        // 創建cell
        viewModel.cellRender = { indexPath,tablleView in
            let cell = tablleView.dequeueReusableCellWithIdentifier("ZECell", forIndexPath: indexPath) as! ZECell
            cell.bigTitleLabel.text = weakSelf?.model.dataArr[indexPath.row].bigTitle
            cell.contextLabel.text = weakSelf?.model.dataArr[indexPath.row].context
            return cell
        }
        // cell點擊事件
        viewModel.cellSlect = { indexPath,tablleView in
            print(weakSelf!.model.dataArr[indexPath.row].context)
        }
        // 模擬網絡請求
        model.getData { (success, status) in
            weakSelf!.viewModel.rawCount = weakSelf!.model.dataArr.count
            weakSelf!.tableView.reloadData()
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

這樣做的優點就是在Controller中很容易處理一些真正核心的步驟,不用寫大量的重復代碼.而且如果把ViewModel抽象好的話,整個工程的TableView都可以用這一個ViewModel,非常方便
最終形態可以做成這樣

掘金新版的設置界面

DEMO地址

本項目demo:https://github.com/Lafree317/ZEMVVM
OC版是一個比較完善的開源庫,大家可以去看一下,我這個是oc版的閹割版
OC版地址:https://github.com/youzan/SigmaTableViewModel

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容