【问题标题】:Passing Data to ViewModel in Swift在 Swift 中将数据传递给 ViewModel
【发布时间】:2018-11-23 23:02:57
【问题描述】:

我是 MVVM 模式的新手,所以请不要评判我。我想要做的是,如果可能的话,我想将数据与 segue 一起传递给 ViewModel,并根据它填充数据。为什么我要这样做,因为假设我有 3 个 ViewController(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)
    }
}

【问题讨论】:

    标签: ios swift uitableview mvvm


    【解决方案1】:

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

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

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

    更新:我认为你的视图模型中最好不要有空模型。那里根本不应该有模型。更好的解决方案可能是概括您获取数据的方式,然后在您实际需要它的视图控制器中获取它。然后,您可以直接为那里的视图创建正确的视图模型。

    【讨论】:

    • 如果你看到我正在按照你说的那样做的代码:)。但是我的问题不同:现在它检索 nil,因为 ViewModel 中没有数据(特别是在 confEvent 或 confMaterials 中)。所以我想以某种方式获取 viewModel 上的数据
    • 我只看到你在注册NIB。您的 ViewController 代码有点短。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 2015-01-20
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    相关资源
    最近更新 更多