MVVM+RxSwift簡単な実践

7702 ワード

1、簡単な説明
  • MVVMを使用してmodel、viewをデカップリングし、多重化の可能性を高めるとともに、controllerの負担を極めて軽減し、ミドルウェアviewModelによってデータソースを処理し、UIをバインドし、論理イベントを処理する.このように,種々の業務が煩雑になると,各業務間のコードを完全に分離し,コードを明確にすることができる.
  • RxSwiftを使用すると、従来のdataSource、delegateなどのエージェントメソッドを置き換えることができ、非同期Event(イベント)シーケンスの応答式プログラミングを行い、便利で速く、論理がより明確になる.
  • コードには優れたオープンソースライブラリ:Kingfisher,SnapKitが使用されています.

  • 2、運行効果
    3、目次構造
    4、ページコード
  • controller
  • //
    //  MainViewController.swift
    //  ss
    //
    //  Created by WES319 on 11/7/18.
    //  Copyright © 2018     . All rights reserved.
    //
    
    import UIKit
    import RxCocoa
    import RxSwift
    import SnapKit
    
    class MainViewController: UIViewController {
    
        var tableView = MainTableView()
        var tableViewModel: MainTableViewModel!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            navigationItem.title = "  "
            
            tableViewModel = MainTableViewModel.init(target: self)
            
            view.addSubview(tableView)
            tableView.snp.makeConstraints { (make) in
                make.edges.equalToSuperview()
            }
        }
    }
    
  • Model
  • //
    //  ProductModel.swift
    //  ss
    //
    //  Created by WES319 on 12/7/18.
    //  Copyright © 2018     . All rights reserved.
    //
    
    import UIKit
    
    class ProductModel: NSObject {
    
        var image: String
        var title: String
        var content: String
        
        required init(image: String, title: String, content: String) {
            self.image = image
            self.title = title
            self.content = content
            super.init()
        }
     
    }
    
  • View
  • //
    //  MainTableView.swift
    //  ss
    //
    //  Created by WES319 on 11/7/18.
    //  Copyright © 2018     . All rights reserved.
    //
    
    import UIKit
    
    class MainTableView: UITableView {
    
        override init(frame: CGRect, style: UITableViewStyle) {
            super.init(frame: frame, style: style)
            
            self.tableFooterView = UIView()
            self.estimatedRowHeight = 100
            self.register(MainTableViewCell.self, forCellReuseIdentifier: MainTableViewCell.cellID)
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    //
    //  MainTableViewCell.swift
    //  ss
    //
    //  Created by WES319 on 11/7/18.
    //  Copyright © 2018     . All rights reserved.
    //
    
    import UIKit
    import Kingfisher
    
    class MainTableViewCell: UITableViewCell {
    
        static let cellID = NSStringFromClass(MainTableViewCell.self)
        
        var mainImageView = UIImageView()
        var titleLabel = UILabel()
        var contentLabel = UILabel()
    
        override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            self.separatorInset = UIEdgeInsetsMake(0, 15, 0, 0)
            
            contentView.addSubview(mainImageView)
            mainImageView.snp.makeConstraints { (make) in
                make.top.left.bottom.equalToSuperview().inset(15)
                make.height.equalTo(80).priority(999)
                make.width.equalTo(mainImageView.snp.height).multipliedBy(16.0/9.0)
            }
            
            titleLabel.font = UIFont.systemFont(ofSize: 15, weight: UIFont.Weight.black)
            contentView.addSubview(titleLabel)
            titleLabel.snp.makeConstraints { (make) in
                make.left.equalTo(mainImageView.snp.right).offset(10)
                make.top.equalTo(mainImageView)
                make.right.lessThanOrEqualToSuperview().inset(10)
            }
            
            contentLabel.textColor = UIColor.gray
            contentLabel.font = UIFont.systemFont(ofSize: 13, weight: UIFont.Weight.light)
            contentLabel.numberOfLines = 2
            contentView.addSubview(contentLabel)
            contentLabel.snp.makeConstraints { (make) in
                make.left.equalTo(titleLabel)
                make.top.equalTo(titleLabel.snp.bottom).offset(5)
                make.right.lessThanOrEqualToSuperview().inset(15)
            }
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        func update(image: String, title: String, content: String) {
            mainImageView.kf.setImage(with: URL.init(string: image))
            titleLabel.text = title
            contentLabel.text = content
        }
    }
  • ViewModel
  • //
    //  MainTableViewModel.swift
    //  ss
    //
    //  Created by WES319 on 11/7/18.
    //  Copyright © 2018     . All rights reserved.
    //
    
    import UIKit
    import RxSwift
    
    class MainTableViewModel: NSObject {
        
        var dataSource = Observable.just([ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "  ", content: "    ,    ,           。            ,          。        ,    。                   。              , 、          ,          ,                。              ,  、  、        ,         。")
            ,ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "  ", content: "    ,    ,           。            ,          。        ,    。                   。              , 、          ,          ,                。              ,  、  、        ,         。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "  ", content: "    ,    ,           。            ,          。        ,    。                   。              , 、          ,          ,                。              ,  、  、        ,         。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "  ", content: "    ,    ,           。            ,          。        ,    。                   。              , 、          ,          ,                。              ,  、  、        ,         。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "  ", content: "    ,    ,           。            ,          。        ,    。                   。              , 、          ,          ,                。              ,  、  、        ,         。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "  ", content: "    ,    ,           。            ,          。        ,    。                   。              , 、          ,          ,                。              ,  、  、        ,         。"),ProductModel.init(image: "http://pic1.win4000.com/wallpaper/d/5279ae86ae5a6.jpg", title: "  ", content: "    ,    ,           。            ,          。        ,    。                   。              , 、          ,          ,                。              ,  、  、        ,         。")])
        weak var target: MainViewController!
        let disposeBag = DisposeBag()
        
        required init(target: MainViewController) {
            self.target = target
            super.init()
            
            //     
            self.dataSource.bind(to: target.tableView.rx.items(cellIdentifier: MainTableViewCell.cellID)) { (_, model, cell: MainTableViewCell) in
                cell.update(image: model.image, title: model.title, content: model.content)
            }.disposed(by: disposeBag)
            
            // tableView    
            self.target.tableView.rx.modelSelected(ProductModel.self).subscribe(onNext: { (model) in
                print(model.title)
            }).disposed(by: disposeBag)
            self.target.tableView.rx.itemSelected.subscribe(onNext: { (indexPath) in
                print(indexPath.row)
                self.target.tableView.deselectRow(at: indexPath, animated: true)
            }).disposed(by: disposeBag)
        }
    }