Section 8/211 menit

8. Router — @MainActor

8. Router — @MainActor

swift
import UIKit

// Router bertanggung jawab untuk navigasi — push, present, dismiss.
// @MainActor karena semua navigasi UIKit harus di main thread.
@MainActor
final class UserListRouter: UserListRoutingLogic {

    // weak reference ke ViewController sebagai source navigasi.
    weak var viewController: UserListViewController?

    // DataStore adalah Interactor itu sendiri — Router membaca data
    // dari sini untuk diteruskan ke destination ViewController.
    weak var dataStore: (any UserListDataStore)?

    // MARK: - UserListRoutingLogic

    func routeToUserDetail(userId: String, userName: String) {
        // Buat destination ViewController.
        // Di aplikasi nyata, ini mungkin diambil dari Storyboard atau factory.
        let detailVC = UserDetailViewController(userId: userId, userName: userName)

        // Navigasi UIKit — aman karena kita di @MainActor.
        viewController?.navigationController?.pushViewController(detailVC, animated: true)
    }
}

// MARK: - Placeholder destination

// Placeholder — di project nyata ini adalah scene VIP terpisah
final class UserDetailViewController: UIViewController {
    private let userId: String
    private let userName: String

    init(userId: String, userName: String) {
        self.userId = userId
        self.userName = userName
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) { fatalError() }

    override func viewDidLoad() {
        super.viewDidLoad()
        title = userName
        view.backgroundColor = .systemBackground
    }
}

Penjelasan poin penting:

  • Router tidak tahu cara fetch data — ia hanya mengambil selectedUser dari dataStore (Interactor) yang sudah diisi sebelumnya oleh Interactor di langkah selectUser.
  • @MainActor di Router adalah keharusan — pushViewController, present, dismiss semuanya harus di main thread.