Reputation:
I am modifying my App in order to implement the MVVM
pattern.
Introduction:
I use WebServices
to get all my data.
At the start of the App, during the loading screen, I make a request to all WebServices so that all my data are available.
For example, when I will tap on the Menu in the App to access a specific Scene, I already have all the data needed, and I pass the model to the corresponding ViewController with the Segue
.
The Question:
The real question is, what is a good way to pass this model data to my ViewModel
?
I am using a struct that implements the Codable
protocol to obtain my model after requesting the web service and parsing the json data.
Here is how my ViewController looks like :
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
}
}
In the ViewModel, I don't know how to declare the Vigilance model or how to properly initialize the ViewModel.
Here is the 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
}
}
Because my Model contains a lot of informations that I currently don't need in this ViewController, I am making an items array so that it is easier to use in my DataSource
.
Here is how my Vigilance Model looks like :
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
}
}
}
}
My first guess on why I can't declare my model without optional is because I don't have custom initializer right ?
But this is not the major issue here.
I would like to know how to pass this model data (previously obtained in this VC from prepareForSegue
) to the ViewModel, and correctly initialize the ViewModel.
If someone can guide me here it would be really appreciated.
I am exploring some obscur parts of the OS and design patterns, trying my best to understand and apply what I am learning.
Upvotes: 1
Views: 3511
Reputation: 3900
And what about the same declaration but in the 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
}
}
Upvotes: 0
Reputation: 3900
My first guess on why I can't declare my model without optional is because I don't have custom initializer right ?
As long as you are initiating your UIViewControllers with segues, you won't be able to use a custom initialiser in which you can pass the desired object. If you want to avoid optional variables, I recommend to write an init function, something like this (and move your VC to a xib file):
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")
}
}
The real question is, what is a good way to pass this model data to my ViewModel?
Once you are initiating your view controller from code instead of segues, you can write some helper functions, usually I put it in a Router (or name how you like) class, like:
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)
Upvotes: 1