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(...) }— karenapresenteradalah property actor (isolated), kita harus mengaksesnya dari dalam isolation domain actor. Cara yang bersih adalah viaasyncmethod.