如何将模型数据从ViewController传递到ViewModel

时间:2018-07-17 13:37:42

标签: ios swift mvvm viewmodel codable

我正在修改我的App,以实现MVVM模式。

简介:

我使用WebServices来获取我的所有数据。

在应用程序启动时,在加载屏幕期间,我向所有Web服务发出请求,以便我的所有数据都可用。

例如,当我点击应用程序中的菜单以访问特定场景时,我已经拥有了所需的所有数据,并使用Segue将模型传递给了相应的ViewController。

问题:

真正的问题是,什么是将模型数据传递到我的ViewModel的好方法?

我正在使用一种实现Codable协议的结构,以在请求Web服务并解析json数据后获取我的模型。

这是我的ViewController的样子:

class VigilanceViewController: UIViewController {

    @IBOutlet var outletTableView: UITableView!

    var vigilance: Vigilance?

    fileprivate let viewModel = VigilanceViewModel()

    override func viewDidLoad() {

        super.viewDidLoad()

        if let vigilance = vigilance {
            // pass data to the viewModel
        }

        outletTableView.dataSource = viewModel
    }
}

在ViewModel中,我不知道如何声明Vigilance模型或如何正确初始化ViewModel。

这是ViewModel:

class VigilanceViewModel: NSObject {

    var items = [VigilanceViewModelItem]()
    var maxVigilance: Int = 0
    var vigilance: Vigilance? = nil

    override init() {
        super.init()

        // Append objects in my items array from the vigilance Model so that the dataSource is ready to go and clean

    }
}

extension VigilanceViewModel: UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return maxVigilance - 1
    }

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = UITableViewCell()

        // TODO

        return cell
    }
}

由于我的模型包含许多当前在此ViewController中不需要的信息,因此我正在制作一个项目数组,以便在DataSource中更易于使用。

这是我的警惕模型的样子:

struct Vigilance: Codable {

    let result: Result

    struct Result: Codable {
        let startDate: Int
        let endDate: Int
        let sendDate: Int
        let advice: String?
        let comment: String?
        let colorMax: Int
        let details: [VigilanceDetails]?

        struct VigilanceDetails: Codable {
            let dptNumber: String
            let dptName: String
            let color: String
            let risks: [Risks]?

            struct Risks: Codable {
                let code: String
                let label: String
            }
        }
    }
}

关于我为什么不能在没有可选参数的情况下声明模型的第一个猜测是,因为我没有自定义初始化程序?

但这不是这里的主要问题。

我想知道如何将模型数据(以前在此VC中从prepareForSegue获得)传递给ViewModel,并正确初始化ViewModel。

如果有人可以在这里指导我,将不胜感激。

我正在探索操作系统和设计模式中一些晦涩难懂的部分,尽我所能来理解和应用所学知识。

2 个答案:

答案 0 :(得分:1)

  

关于我为什么不能在没有可选参数的情况下声明模型的第一个猜测是   因为我没有自定义的初始化程序?

只要您使用segues启动UIViewControllers,就将无法使用自定义初始化程序来传递所需的对象。 如果要避免使用可选变量,建议您编写一个类似以下内容的init函数(并将VC移至xib文件):

class ViewController: UIViewController {
    let param: String

    init(param: String) {
        self.param = param
        super.init(nibName: "YourViewControllerNibsName", bundle: Bundle.main)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
  

真正的问题是,什么是将模型数据传递到ViewModel的好方法?

一旦您从代码而不是segues启动视图控制器,就可以编写一些辅助函数,通常我将其放在Router(或命名)类中,例如:

class AppRouter {
    // Return UIViewController not to expose the type of ViewController
    static func getViewController(with param: String) -> UIViewController {
        return ViewController(param: param)
    }
}

// Using it from an another VC
let actualVC: UIViewController!
let vcToPresent = AppRouter.getViewController(with: "yourParam")
actualVC.present(vcToPresent, animated: true, completion: nil)

答案 1 :(得分:0)

  

除了ViewModel之外,相同的声明又如何呢?

class VigilanceViewModel: NSObject {
    let items: [VigilanceViewModelItem]
    let maxVigilance: Int
    let vigilance: Vigilance

    init(items: [VigilanceViewModelItem], vigilance: Vigilance) {
        self.items = items
        self.vigilance = vigilance
        maxVigilance = vigilance.max
    }
}