My project is structured in MVVM architecture and I'm using the Coordinator design pattern to handle navigation (all programmatically, no Storyboards involved).
It consists of several TableViewControllers with users, albums, photos, posts and comments, each one with its own TableViewController. In each user cell, you can access its albums and posts. Selecting an album or a post, you can see more details, etc...
I'm fetching the data from {JSON} Placeholder API and displaying it on the table views, but can't seem to be able to pass data from the first to the next ones. Since I'm working with a Navigation Controller, and there are no segues, I can't use prepare(for segue:)
to setup the next table view before navigating from one view to the other.
I trigger navigation through the functions didTapAlbums(with userId: Int, by name: String)
and didTapPosts(with userId: Int, by name: String)
which calls the method eventOcurred(with: Event)
setup in my Coordinator protocol, that pushes the next TableViewController into the NavigationController.
Here's my Main Coordinator class:
import UIKit
class MainCoordinator: Coordinator {
var navigationController: UINavigationController
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func eventOccurred(with type: Event) {
switch type {
case .didTapAlbums:
var albumsTableViewController: UITableViewController & Coordinating = AlbumTableViewController()
albumsTableViewController.coordinator = self
navigationController.pushViewController(albumsTableViewController, animated: true)
case .didTapAlbumCell:
var photoTableViewController: UITableViewController & Coordinating = PhotoTableViewController()
photoTableViewController.coordinator = self
navigationController.pushViewController(photoTableViewController, animated: true)
case .didTapPhotoCell:
var detailsViewController: UIViewController & Coordinating = DetailsViewController()
detailsViewController.coordinator = self
navigationController.pushViewController(detailsViewController, animated: true)
case .didTapPosts:
var postsTableViewController: UITableViewController & Coordinating = PostTableViewController()
postsTableViewController.coordinator = self
navigationController.pushViewController(postsTableViewController, animated: true)
case .didTapPostCell:
var commentTableViewController: UITableViewController & Coordinating = CommentTableViewController()
commentTableViewController.coordinator = self
navigationController.pushViewController(commentTableViewController, animated: true)
}
}
func start() {
var challengeViewController: UITableViewController & Coordinating = ChallengeViewController()
challengeViewController.coordinator = self
navigationController.setViewControllers([challengeViewController], animated: false)
}
}
Here's the first TableViewController, which displays the users:
import Alamofire
import UIKit
class ChallengeViewController: UITableViewController, Coordinating {
var coordinator: Coordinator?
let userViewModel = UserViewModel()
var users = [User]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.register(UserTableViewCell.self, forCellReuseIdentifier: "UserCell")
tableView.rowHeight = 233
userViewModel.fillUsers { data in
self.users = data
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
}
// MARK: - TableView DataSource
extension ChallengeViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath) as! UserTableViewCell
let user = users[indexPath.row]
cell.selectionStyle = .none
cell.id = user.id
cell.initialsLabel.text = String(user.name.prefix(2))
cell.nameLabel.text = user.name
cell.userNameLabel.text = user.username
cell.emailLabel.text = user.email
cell.phoneLabel.text = user.phone
cell.delegate = self
cell.backgroundColor = indexPath.row % 2 == 0 ? .white : UIColor(white: 0.667, alpha: 0.2)
return cell
}
}
// MARK: - Navigation
extension ChallengeViewController: UserTableViewCellDelegate {
func didTapAlbums(with userId: Int, by name: String) {
coordinator?.eventOccurred(with: .didTapAlbums)
}
func didTapPosts(with userId: Int, by name: String) {
coordinator?.eventOccurred(with: .didTapPosts)
}
}
All I want to do is pass userId
and name
values to the next Controller.
EDIT: Coordinator and Coordinating protocols
import UIKit
enum Event {
case didTapAlbums, didTapPosts, didTapAlbumCell, didTapPhotoCell, didTapPostCell
}
protocol Coordinator {
var navigationController: UINavigationController { get set }
func eventOccurred(with type: Event)
func start()
}
protocol Coordinating {
var coordinator: Coordinator? { get set }
}