Section 3/211 menit
3. Protocols
3. Protocols
swift
import UIKit
// MARK: - Display Logic (View ← Presenter)
// Protocol ini dimiliki oleh View.
// Semua method wajib @MainActor karena memanggil UIKit.
// Presenter akan await method ini ketika memanggilnya dari @MainActor-nya sendiri.
@MainActor
protocol UserListDisplayLogic: AnyObject {
func displayUsers(_ viewModel: UserList.FetchUsers.ViewModel)
func displayLoading(_ isLoading: Bool)
func displayError(message: String)
func displaySelectedUser(_ viewModel: UserList.SelectUser.ViewModel)
}
// MARK: - Business Logic (Interactor ← View)
// Protocol ini dimiliki oleh Interactor.
// Method dibuat async karena Interactor adalah actor —
// memanggilnya dari @MainActor ViewController butuh await.
protocol UserListBusinessLogic: AnyObject, Sendable {
func fetchUsers(request: UserList.FetchUsers.Request) async
func selectUser(request: UserList.SelectUser.Request) async
}
// MARK: - Presentation Logic (Presenter ← Interactor)
// Protocol ini dimiliki oleh Presenter.
// @MainActor di sini karena Presenter harus memformat dan langsung
// memanggil View yang juga @MainActor.
// Ketika Interactor (actor) memanggil method ini, Swift otomatis
// menjadwalkan eksekusi ke main thread lewat await.
@MainActor
protocol UserListPresentationLogic: AnyObject {
func presentUsers(_ response: UserList.FetchUsers.Response)
func presentLoading(_ isLoading: Bool)
func presentError(_ error: Error)
func presentSelectedUser(_ response: UserList.SelectUser.Response)
}
// MARK: - Routing Logic (Router ← View)
// @MainActor karena navigasi selalu butuh UIKit (push, present, dll)
@MainActor
protocol UserListRoutingLogic: AnyObject {
func routeToUserDetail(userId: String, userName: String)
}
// MARK: - Data Passing (Router ← View, shared dengan Interactor)
// DataStore adalah jembatan data antara View dan Router.
// Disimpan di Interactor dan dibaca oleh Router saat navigasi.
// Sendable karena bisa diakses dari beberapa isolation context.
protocol UserListDataStore: AnyObject {
var selectedUser: User? { get }
}
Penjelasan poin penting:
@MainActordi protocol berarti semua conforming type harus memenuhi kontrak tersebut di main thread. Ketika Interactor (actor) memanggilpresenter.presentUsers(...), Swift akan otomatis menjadwalkan ke main thread — tanpa kita perluDispatchQueue.main.async.SendablediUserListBusinessLogicmemungkinkan protocol ini disimpan di dalamactorsebagai property. Tanpa ini, menyimpan referensi ke protocol di dalam actor akan menyebabkan compile error di Swift 6.asyncmethod diUserListBusinessLogicmerefleksikan kenyataan bahwa Interactor adalahactor— memanggilnya dari konteks berbeda memerlukanawait.