Reputation: 470
I don't know how to pass data from my viewModel to my view and finally show the data in the view, my view model class is:
class MainViewModel {
let sessionController: SessionController
weak var mainViewCoordinator: MainViewCoordinator?
public var fakeUsers: [User]?
init(sessionController: SessionController = SessionController()) {
self.sessionController = sessionController
}
func viewDidLoad() {
Service.instance.execute(resource: User.fake) { (result) in
print("\n result \(result)\n")
self.fakeUsers = result.value
}
}
}
I'm using Unbox Swift JSON decoder, and the printed result is is and array of User objects something like this:
([
User(id: "5851ac2615801e2348e4ea07",
birthDate: "2016-09-17T07:22:09.985Z",
msisdn: "912 065 979",
email: "[email protected]",
profileImageUrl: "https://s3.amazonaws.com/...",
repPoints: 41607,
created: "2016-12-14T20:31:34.185Z",
displayName: "Victoria Escobedo"),
User(id: "5851ac2615801e2348e4ea09",
birthDate: "2016-05-06T11:38:23.678Z",
msisdn: "958842030",
email: "[email protected]",
profileImageUrl: "https://s3.amazonaws.com/...",
repPoints: 71408,
created: "2016-12-14T20:31:34.198Z",
displayName: "Gonzalo Rascón"),
User(id: "5851ac2615801e2348e4ea08",
birthDate: "2016-05-29T18:12:32.423Z",
msisdn: "905534639",
email: "[email protected]",
profileImageUrl: "https://s3.amazonaws.com/...",
repPoints: 24164,
created: "2016-12-14T20:31:34.195Z",
displayName: "Ramiro Dueñas"),
...
])
And I would like to pass the result to the View Layer (MainViewController) to show each User in table view cells:
class MainViewController: UIViewController, UITableViewDataSource {
@IBOutlet var tableview:UITableView!
var viewModel: MainViewModel = MainViewModel()
override func viewDidLoad() {
super.viewDidLoad()
viewModel.viewDidLoad()
self.tableview?.reloadData()
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Action", style: .plain, target: self, action: #selector(action))
}
func action() {
viewModel.userDidSelectItem(identifier: "xxxx")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.fakeUsers?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) ->UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "fakeUserObjectCell") as! MainTableViewCell
cell.fakeUserObject = viewModel.fakeUsers?[(indexPath as NSIndexPath).row]
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detailSegue" {
let detailMainViewController = segue.destination as! DetailMainViewController
if let indexPath = tableview.indexPath(for: sender as! MainTableViewCell) {
detailMainViewController.id = viewModel.fakeUsers?[(indexPath as NSIndexPath).row].id
}
}
}
}
I know I have to implement self.tableview?.reloadData()
to show the fakeusers but I don't know how to pass the data and finally show it.
Upvotes: 0
Views: 98
Reputation: 5747
The following Service.instance.execute()
in viewModel.viewDidLoad()
is a async call. It have not completed the fetching and you have call self.tableview?.reloadData()
Therefore this likely resulted in 0
rows.
I would suggest to change ViewModel
viewDidLoad()
to a completion call
func viewDidLoad() {
Service.instance.execute(resource: User.fake) { (result) in
print("\n result \(result)\n")
self.fakeUsers = result.value
}
}
Like this:
func loadUsers(completion: () -> ()) {
Service.instance.execute(resource: User.fake) { (result) in
print("\n result \(result)\n")
self.fakeUsers = result.value
completion()
}
}
Therefore in the MainViewController
, viewDidLoad
, you can change the call to only reloadData()
when is ready.
override func viewDidLoad() {
super.viewDidLoad()
viewModel.loadUsers {
self.tableview?.reloadData()
}
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Action", style: .plain, target: self, action: #selector(action))
}
Upvotes: 1
Reputation: 1805
public var fakeUsers: [User]?
in MainViewModel
fakeUsers
in MainViewModel
's viewDidLoad()
fakeUsers
var in MainViewController
numberOfRowsInSection
in MainViewController
now returns the count of fakeUsers
set by MainViewModel
like:func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.fakeUsers?.count ?? 0
}
Similarly, for cellForRowAt indexPath:
EDIT:
The Service.instance.execute
API call won't return immediately, but when it does, the data array should be updated with new content & the table requested to be refreshed.
But now the problem is that we cannot have table
access in MainViewModel
.
So, when the Service
fetch completes, we can notify MainViewController
to perform a table.reloadData()
I hope you can come up with the code for this bit, you'll need to start here:
class MainViewModel {
...
func viewDidLoad() {
Service.instance.execute(resource: User.fake) { (result) in
print("\n result \(result)\n")
self.fakeUsers = result.value
// Edu, the table refresh notification is to be fired from here
}
}
}
Upvotes: 0