美文网首页Swift项目相关
swift ~ MVVM之UITableView绑定

swift ~ MVVM之UITableView绑定

作者: RudyHao | 来源:发表于2018-06-14 15:38 被阅读193次

    本篇讲解一行代码搞定UITableView绑定

    • 原来我们的UITableView可能是这样的
    final class ViewController: UIViewController{
        //数据源
        var data = []
    
        /**
         * 创建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()
            /**
         * 创建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实现ReactiveView协议《可读源码&改造源码》
            self.tbAdapter =  TableViewBindingAdapter<Model>(
            tableView: self.tableView,
            sourceSignal: (viewModel.dataSource),
            nibName: TableViewCell.getClassName())
        }
    }
    

    怎么样,是不是精神气爽?哈哈,感谢Rx给开发带来的便捷...
    基本思路: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: 数据源
        ///   - 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")
        }
    }
    

    持续分享源码待续...

    相关文章

      网友评论

        本文标题:swift ~ MVVM之UITableView绑定

        本文链接:https://www.haomeiwen.com/subject/uhjyeftx.html