Section 9/211 menit

9. Configurator — Dependency Injection

9. Configurator — Dependency Injection

swift
import UIKit

// Configurator bertugas merakit semua komponen VIP dan menghubungkannya.
// Ini adalah satu-satunya tempat di mana semua dependensi dibuat dan disambungkan.
// Di aplikasi nyata, ini bisa digantikan oleh DI container.
@MainActor
enum UserListConfigurator {

    // Factory method yang mengembalikan ViewController yang sudah ter-wire penuh.
    static func makeViewController() -> UserListViewController {

        // 1. Buat semua komponen
        let viewController = UserListViewController()
        let interactor = UserListInteractor()
        let presenter = UserListPresenter()
        let router = UserListRouter()

        // 2. Sambungkan View → Interactor
        viewController.interactor = interactor

        // 3. Sambungkan View → Router
        viewController.router = router

        // 4. Sambungkan Interactor → Presenter
        // 'await' tidak diperlukan di sini — kita sedang setup, belum ada concurrent access.
        // Presenter assignment ke actor property dilakukan melalui isolasi actor Interactor.
        // Ini terjadi sebelum ViewController ditampilkan, jadi aman.
        Task {
            // Kita perlu masuk ke isolation domain Interactor untuk assign presenter-nya.
            await setPresenter(presenter, on: interactor)
        }

        // 5. Sambungkan Presenter → View
        presenter.viewController = viewController

        // 6. Sambungkan Router → View & DataStore
        router.viewController = viewController
        router.dataStore = interactor

        return viewController
    }

    // Helper untuk assign presenter ke Interactor dari luar actor.
    // Ini adalah cara yang benar untuk mengakses isolated property actor dari luar.
    private static func setPresenter(
        _ presenter: any UserListPresentationLogic,
        on interactor: UserListInteractor
    ) async {
        await interactor.setPresenter(presenter)
    }
}

Tambahkan method setPresenter ke UserListInteractor:

swift
// Tambahkan ke extension UserListInteractor
extension UserListInteractor {
    // Method ini berjalan di dalam isolation domain actor — aman untuk assign.
    func setPresenter(_ presenter: any UserListPresentationLogic) {
        self.presenter = presenter
    }
}

Penggunaan di AppDelegate / SceneDelegate:

swift
@MainActor
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    ) {
        guard let windowScene = (scene as? UIWindowScene) else { return }

        // Buat ViewController melalui Configurator — semua wiring terjadi di sini.
        let userListVC = UserListConfigurator.makeViewController()
        let navController = UINavigationController(rootViewController: userListVC)

        window = UIWindow(windowScene: windowScene)
        window?.rootViewController = navController
        window?.makeKeyAndVisible()
    }
}

Penjelasan poin penting:

  • Configurator adalah satu-satunya tempat yang tahu tentang concrete type — semua komponen lain hanya tahu tentang protocol. Ini memudahkan testing (tinggal ganti concrete type dengan mock).
  • Task { await setPresenter(...) } — karena presenter adalah property actor (isolated), kita harus mengaksesnya dari dalam isolation domain actor. Cara yang bersih adalah via async method.