Section 2/211 menit

2. Models & Namespace

2. Models & Namespace

swift
import Foundation

// MARK: - Domain Model

// Sendable wajib karena User akan melewati batas isolation:
// dari Worker (actor) → Interactor (actor) → Presenter (@MainActor)
struct User: Sendable, Equatable {
    let id: String
    let name: String
    let email: String
    let avatarURL: URL?
}

// MARK: - VIP Namespace

// Enum kosong sebagai namespace — pola Clean Swift untuk menghindari
// nama bertabrakan dan membuat struktur data per use-case lebih jelas
enum UserList {

    // Setiap use-case punya tiga lapisan data:
    // Request  → dari View ke Interactor
    // Response → dari Interactor ke Presenter (data mentah)
    // ViewModel → dari Presenter ke View (sudah diformat, siap tampil)

    enum FetchUsers {

        // Request: data apa yang View kirim ke Interactor.
        // Kosong di sini karena fetch tidak butuh parameter.
        // Tetap dibuat struct untuk konsistensi dan kemudahan ekstensi di masa depan.
        struct Request: Sendable {}

        // Response: data mentah dari business logic.
        // Sendable karena dikirim dari Interactor (actor) ke Presenter (@MainActor).
        struct Response: Sendable {
            let users: [User]
        }

        // ViewModel: data yang sudah siap ditampilkan.
        // Hanya berisi String/primitif — Presenter yang bertanggung jawab format.
        struct ViewModel: Sendable {
            struct DisplayedUser: Sendable {
                let id: String
                let fullName: String        // sudah di-capitalize
                let emailLabel: String      // sudah diformat "Email: ..."
                let avatarURL: URL?
            }
            let displayedUsers: [DisplayedUser]
        }
    }

    enum SelectUser {

        // Request berisi index yang di-tap user di tableView
        struct Request: Sendable {
            let index: Int
        }

        // Response berisi User yang dipilih untuk diteruskan ke Router
        struct Response: Sendable {
            let selectedUser: User
        }

        struct ViewModel: Sendable {
            let userId: String
            let userName: String
        }
    }
}

Penjelasan poin penting:

  • Sendable di setiap model adalah wajib di Swift 6. Tanpa ini, compiler akan error ketika model dikirim melewati batas isolation (misalnya dari actor Interactor ke @MainActor Presenter).
  • Namespace enum UserList adalah konvensi Clean Swift (VIP). Setiap fitur punya namespacenya sendiri sehingga nama Request, Response, ViewModel tidak bertabrakan di seluruh project.
  • Request kosong tetap dibuat — agar jika suatu saat butuh parameter (filter, pagination), tidak perlu mengubah signature seluruh chain.