swift ~ MVVM之UITableView綁定

本篇講解一行代碼搞定UITableView綁定

  • 原來我們的UITableView可能是這樣的
final class ViewController: UIViewController{
    //數(shù)據(jù)源
    var data = []

    /**
     * 創(chuàng)建tableView
     */
    lazy var tableView: UITableView! = {
        let tableView = UITableView()
        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(nibWithCellClass: TableViewCell.self)
        self.view.addSubview(tableView)
        return tableView
    }()
}

extension ViewController: UITableViewDelegate {
    public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 60
    }
    
    public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 30
    }
}

extension ViewController: UITableViewDataSource {
    public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withClass: SVW_PowerListTableViewCell.self)
        if indexPath.row >= data.count {
            fatalError("index over items court")
        }
        
        guard let item = data.item(at: indexPath.row) else {
            fatalError("cell model is empty")
        }
        do {
            try cell?.setLayoutModel(item)
        } catch {
            fatalError(error.localizedDescription)
        }
        return cell!
    }
}

對洞渤,我們大多的UITableView都是長這樣子额各,而且一個app可能有很多這樣的代碼脏答;有了Rx就可以一行代碼搞定啦...請看碼:

  • 改造后的代碼是這樣的:
final class ViewController: UIViewController{
     var tbAdapter:TableViewBindingAdapter<Model>?
     var viewModel = ViewModel()
        /**
     * 創(chuàng)建tableView
     */
    lazy var tableView: UITableView! = {
        let tableView = UITableView()
        //??????請注意這三行不需要了
        //tableView.delegate = self
        //tableView.dataSource = self
        //tableView.register(nibWithCellClass: TableViewCell.self)
        self.view.addSubview(tableView)
        return tableView
    }()
    override func viewDidLoad() {
        super.viewDidLoad()
        //別看這么長驯用,實際就一行??
        //同時需要TableViewCell實現(xiàn)ReactiveView協(xié)議《可讀源碼&改造源碼》
        self.tbAdapter =  TableViewBindingAdapter<Model>(
        tableView: self.tableView,
        sourceSignal: (viewModel.dataSource),
        nibName: TableViewCell.getClassName())
    }
}

怎么樣庶弃,是不是精神氣爽?哈哈尺碰,感謝Rx給開發(fā)帶來的便捷...
基本思路:Android的ListView適配器模式
資料來源鏈接
思路拓展:可能有同學會問我想在tableview添加更復雜的功能咋辦挣棕?so easy,重寫一個適合自己需要的adapter即可

TableViewBindingAdapter源代碼

//
//  TableViewBindingAdapter.swift
//  ReactiveSwiftFlickrSearch
//
//  Created by Colin Eberhardt on 15/07/2014.
//  Copyright (c) 2014 Colin Eberhardt. All rights reserved.
//

import Foundation
import UIKit
import RxSwift
import RxCocoa


protocol ReactiveView {
    func getCellHeight<M>(model: M)->CGFloat
    func bindViewModel<M>(model: M)
}


// a helper that makes it easier to bind to UITableView instances
// see: http://www.scottlogic.com/blog/2014/05/11/reactivecocoa-tableview-binding.html
class TableViewBindingAdapter<T>: NSObject, UITableViewDataSource, UITableViewDelegate {
  
  //MARK: Properties
    private var disposeBag = DisposeBag()

    var delegate: UITableViewDelegate?
  
    private let tableView: UITableView
    private let templateCell: UITableViewCell
    private let rowCommand: PublishSubject<AnyObject>?
    private let cellCommand: PublishSubject<AnyObject>?
    private let sectionView: UIView?

    private var data: [T]
  
    /// table adapter
    ///
    /// - Parameters:
    ///   - tableView: tableview
    ///   - sourceSignal: 數(shù)據(jù)源
    ///   - nibName: tableviewcell xib
    ///   - rowCommand: 行點擊時間
    ///   - cellCommand: 行內按鈕點擊事件
    ///   - sectionView: table section
    init(tableView: UITableView, sourceSignal: Observable<[T]?>, nibName: String, rowCommand: PublishSubject<AnyObject>? = nil,cellCommand: PublishSubject<AnyObject>? = nil, sectionView:UIView? = nil) {
    self.tableView = tableView
    self.data = []
    self.rowCommand = rowCommand
    self.cellCommand = cellCommand
    self.sectionView = sectionView
        
    let nib = UINib(nibName: nibName, bundle: nil)
    // create an instance of the template cell and register with the table view
    templateCell = nib.instantiate(withOwner: nil, options: nil)[0] as! UITableViewCell
    tableView.register(nib, forCellReuseIdentifier: NSStringFromClass(templateCell.classForCoder))
    
    super.init()
    
    sourceSignal.subscribe(onNext: {[weak self] (dic) in
        if dic != nil{
            self?.data = dic!
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: {
                self?.tableView.reloadData()
            })
        }
    }).disposed(by: self.disposeBag)
    
    tableView.dataSource = self
    tableView.delegate = self
  }
  
  //MARK: Private
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        if (self.sectionView != nil) {
            return self.sectionView!.height
        }else{
            return 0
        }
    }
    
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        if (self.sectionView != nil) {
            return self.sectionView
        }else{
            return nil
        }
    }
  
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return data.count
  }

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let item: T = data[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(templateCell.classForCoder))! as UITableViewCell
    cell.event = self.cellCommand
    if let reactiveView = cell as? ReactiveView {
        reactiveView.bindViewModel(model: item)
    }
    return cell
  }
  
  func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(templateCell.classForCoder))! as UITableViewCell
    let item: T = data[indexPath.row]
    if let reactiveView = cell as? ReactiveView {
       
        return reactiveView.getCellHeight(model: item)
    }
    else{
        return templateCell.frame.size.height
    }
  }
  
  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if rowCommand != nil {
        rowCommand?.onNext(data[indexPath.row] as AnyObject)
    }
    tableView.deselectRow(at: indexPath, animated: true)
  }
  
  func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if self.delegate?.responds(to: #selector(UIScrollViewDelegate.scrollViewDidScroll(_:))) == true {
      self.delegate?.scrollViewDidScroll?(scrollView);
    }
  }
    
    deinit{
        print("******************" + String(describing: self)+"******************deinit")
    }
}

持續(xù)分享源碼待續(xù)...

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末亲桥,一起剝皮案震驚了整個濱河市洛心,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌题篷,老刑警劉巖词身,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異番枚,居然都是意外死亡法严,警方通過查閱死者的電腦和手機损敷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來深啤,“玉大人拗馒,你說我怎么就攤上這事∷萁郑” “怎么了诱桂?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長呈昔。 經(jīng)常有香客問我挥等,道長,這世上最難降的妖魔是什么堤尾? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任肝劲,我火速辦了婚禮,結果婚禮上郭宝,老公的妹妹穿的比我還像新娘涡相。我一直安慰自己,他們只是感情好剩蟀,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布催蝗。 她就那樣靜靜地躺著,像睡著了一般育特。 火紅的嫁衣襯著肌膚如雪丙号。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天缰冤,我揣著相機與錄音犬缨,去河邊找鬼。 笑死棉浸,一個胖子當著我的面吹牛怀薛,可吹牛的內容都是我干的。 我是一名探鬼主播迷郑,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼枝恋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了嗡害?” 一聲冷哼從身側響起焚碌,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎霸妹,沒想到半個月后十电,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年鹃骂,在試婚紗的時候發(fā)現(xiàn)自己被綠了台盯。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡畏线,死狀恐怖爷恳,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情象踊,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布棚壁,位于F島的核電站杯矩,受9級特大地震影響,放射性物質發(fā)生泄漏袖外。R本人自食惡果不足惜史隆,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望曼验。 院中可真熱鬧泌射,春花似錦、人聲如沸鬓照。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豺裆。三九已至拒秘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間臭猜,已是汗流浹背躺酒。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蔑歌,地道東北人羹应。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像次屠,于是被迫代替她去往敵國和親园匹。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內容

  • 1劫灶、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,979評論 3 119
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫偎肃、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,098評論 4 62
  • 軍旅至將浑此,兵不白當累颂。和平有屏,軍功無尚。幾年不短紊馏,一生不長料饥。衛(wèi)士守土,國防無疆朱监!
    悟風塵閱讀 124評論 0 0
  • 西涼水哥閱讀 521評論 0 50
  • 累了岸啡。
    子曰慎獨閱讀 137評論 1 2