在Swift中将数据传递给ViewModel

时间:2018-06-14 08:24:12

标签: ios swift uitableview mvvm

我是MVVM模式的新手,所以请不要评判我。我想要做的是,如果可以使用ViewModel并且基于此填充数据,我想用segue传递数据。为什么我要这样做,因为我想有3个ViewControllers(A,B,C)。在ViewController上我从Realm数据库获取数据,然后我用segues传递这些数据,我真的不想改变那个结构。但是,如果你有更好的建议,请告诉我。

这是我的代码:

//MARK:- ViewModelItemTypes
enum EventViewModelItemType {
    case description
    case materials
}

//MARK:- ViewModel

class EventViewModel: NSObject {
    var items = [EventViewModelItem]()

    override init() {
        super.init()

        let confEvent = ConferenceEvents()
        let confMaterials = EventMaterials()

        if let descriptionText = confEvent.eventDescription {
            let descriptionItem = EventViewModelDescItem(descriptionText: descriptionText)
            items.append(descriptionItem)
        }

        if let materials: EventMaterials = confMaterials {
            let materialsItem = EventViewModeMaterialsItem(materials: [materials])
            items.append(materialsItem)
        }
    }
}

extension EventViewModel: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return items.count
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items[section].rowCount
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let item = items[indexPath.row]
        switch item.type {
        case .description:
            if let cell = tableView.dequeueReusableCell(withIdentifier: Identifiers.confEventDescriptionCell, for: indexPath) as? ConfEventDescTCell {
                cell.item = item
                return cell
            }
        case .materials:
            if let item = item as? EventViewModeMaterialsItem, let cell = tableView.dequeueReusableCell(withIdentifier: Identifiers.confEventMaterialCell, for: indexPath) as? ConfEventMatTCell {
                let materials = item.materials[indexPath.row]
                cell.material = materials
                return cell
            }
        }
        return UITableViewCell()
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return items[section].sectionTitle
    }
}

//MARK:- ViewModelItem Protocol
protocol EventViewModelItem {
    var type: EventViewModelItemType { get }
    var rowCount: Int { get }
    var sectionTitle: String { get }
}

extension EventViewModelItem {
    var rowCount: Int {
        return 1
    }
}

//MARK:- View Model Items
class EventViewModelDescItem: EventViewModelItem {
    var type: EventViewModelItemType {
        return .description
    }

    var sectionTitle: String {
        return "Description"
    }

    var descriptionText: String

    init(descriptionText: String) {
        self.descriptionText = descriptionText
    }
}

class EventViewModeMaterialsItem: EventViewModelItem {
    var type: EventViewModelItemType {
        return .materials
    }
    var sectionTitle: String {
        return "Materials"
    }
    var rowCount: Int {
        return materials.count
    }
    var materials: [EventMaterials]

    init(materials: [EventMaterials]) {
        self.materials = materials
    }
}

正如您所看到的,我有confEvent和confMaterials的空实例。他们是我的模特,我正在使用RealmSwift。 我的建议是用数据填充这些模型,但我不知道该怎么做。这就是我希望你们帮助我的地方。

这是我的ViewController代码:

class ViewController: UIViewController {

    @IBOutlet private weak var tableView: UITableView!

    var viewModel = EventViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.sectionHeaderHeight = 70
        tableView.separatorStyle = .none
        tableView.dataSource = viewModel
        tableView?.estimatedRowHeight = 100
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.register(ConfEventDescTCell.nib, forCellReuseIdentifier: Identifiers.confEventDescriptionCell)
        tableView.register(ConfEventMatTCell.nib, forCellReuseIdentifier: Identifiers.confEventMaterialCell)

    }
}

UITableViewCells: 第一个UITableViewCell

import UIKit

class ConfEventDescTCell: UITableViewCell {

    @IBOutlet private weak var descriptionTextView: UITextView!

    var item: EventViewModelItem? {
        didSet {
            configureUI()
        }
    }

    private func configureUI() {
        guard let item = item as? EventViewModelDescItem else { return }
        DispatchQueue.main.async {
            self.descriptionTextView.text = item.descriptionText
        }
    }

    static var nib:UINib {
        return UINib(nibName: identifier, bundle: nil)
    }

    static var identifier: String {
        return String(describing: self)
    }
}

第二个UITableViewCell

import UIKit

class ConfEventMatTCell: UITableViewCell {

    @IBOutlet private weak var matTitle: UIImageView!

    var material: EventMaterials? {
        didSet {
            guard let material = material else { return }
            configureUI()

        }
    }

    private func configureUI() {
        guard let material = material else { return }
        DispatchQueue.main.async {
            self.matTitle.text = material.materialTitle
        }
    }

    static var nib: UINib {
        return UINib(nibName: identifier, bundle: nil)
    }

    static var identifier: String {
        return String(describing: self)
    }
}

1 个答案:

答案 0 :(得分:0)

您应该将viewModel传递到创建它的ConfEventDescTCell

因此,例如在cellForRowAtIndexPath中,您将创建一个新的UITableViewCell,然后使用方法调用或作为属性或其他方式将viewmodel实例传递给它。问题是有很多方法可以做到这一点。

关键是在显示单元格之前,您将从特定的视图模型中检索信息以对其进行自定义。

更新:我认为在您的viewmodel中没有空模型是最好的。根本就没有模型。更好的解决方案可能是概括您获取数据的方式,然后在实际需要它的viewcontroller中获取它。然后,您可以直接为您拥有的视图创建正确的视图模型。