Model layer
class MyWebService {
static let shared = MyWebService
// URLSession instance / configuration
// JSONDecoder/Encoder configuration
// Environments (dev, qa, prod, test / mocks)
// Requests and token management
var token: String? = nil
func request<T: Codable>(/* path, method, query, payload*/) async throws -> T { ... }
func requestAccess(username: String, password: String) async throws { ... }
func revokeAccess() async throws { ... }
}
struct Product: Identifiable, Hashable, Codable {
let id: Int
let name: String
let description: String
let image: URL?
let price: Double
let inStock: Bool
}
class ProductStore: ObservableObject {
@Published var products: [Product] = []
enum Phase {
case waiting
case success
case failure(Error)
}
@Published var phase: Phase? = nil
func load() async {
do {
phase = .waiting
products = try await MyWebService.shared.request(path: “products”)
phase = .success
} catch {
phase = .failure(error)
}
}
}
View layer
struct ProductList: View {
@StateObject var store = ProductStore()
var body: some View {
List { ... }
.task {
await store.load()
}
.navigationDestination(for: Product.self) { product in
ProductView(product: product)
// (--- OPTIONAL ---)
// Only if you need to make changes to the store and that store its not already shared
// ProductView(product: product)
// .environmentObject(store)
// (--- OR ---)
// ProductView(product: product, store: store)
}
}
}
struct ProductView: View {
var product: Product
// (--- OR ---)
// If you make changes to the product
// @State var product: Product
// (--- OPTIONAL ---)
// Only if you need to make changes to the store and that store its not already shared
// @EnvironmentObject private var store: ProductStore
// (--- OR ---)
// @ObservedObject var store: ProductStore
var body: some View {
ScrollView { ... }
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags: