今天開始我們要來介紹App 常用功能,首先會從專案架構講起。
提到專案架構就不得不提到MVVM,所以今天我們會針對MVVM進行介紹。
MVVM 是一種常見的專案架構模式,主要目的是 分離畫面 (UI) 與邏輯 (Logic),降低耦合、方便測試,讓程式更乾淨、可維護。
MVVM 分成三層:
好處:
在 MVVM 架構 中,ViewModel 的責任就是 管理狀態 並 通知 View 更新。
而在 SwiftUI 中,最常見的方式是搭配 Combine 框架:
@Published 發布狀態變更@StateObject 或 @ObservedObject 來接收資料更新import SwiftUI
import Combine
class CounterViewModel: ObservableObject {
    // 使用 @Published 讓數值改變時能發出通知
    @Published var count = 0
    func increment() {
        count += 1
    }
}
struct CounterView: View {
    // 使用 @StateObject 讓 View 訂閱 ViewModel 的資料流
    @StateObject var viewModel = CounterViewModel()
    var body: some View {
        VStack {
            Text("目前數字:\(viewModel.count)")
                .font(.largeTitle)
            Button("加一") {
                viewModel.increment()
            }
        }
    }
}

@Published var count 是一個 Publisher。increment() 改變數值時,count 會透過 Combine 發出 新的值。@StateObject 自動訂閱這個 Publisher,讓 View 收到新值並重新渲染。ViewModel
import SwiftUI
import Combine
class LoginViewModel: ObservableObject {
    // 使用者輸入
    @Published var username: String = ""
    @Published var password: String = ""
        
    // 狀態
    @Published var loginMessage: String = ""
        
        
    func login() {
        if username == "admin" && password == "1234" {
            loginMessage = "登入成功"
        } else {
            loginMessage = "帳號或密碼錯誤"
        }
    }
}
View
struct LoginView: View {
    @StateObject private var viewModel = LoginViewModel()
    
    var body: some View {
        VStack(spacing: 20) {
            TextField("帳號", text: $viewModel.username)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding(.horizontal)
            
            SecureField("密碼", text: $viewModel.password)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding(.horizontal)
            
            Button("登入") {
                viewModel.login()
            }
            .padding()
            
            Text(viewModel.loginMessage)
                .foregroundColor(.blue)
        }
        .padding()
    }
}

登入成功

登入失敗

@Published username、@Published password 發出更新。loginMessage,畫面立即反映結果。LoginViewModel,負責處理登入邏輯LoginView,負責顯示 UI 並觸發事件@Published、@StateObject、@ObservedObject) 來建立資料流明天預計會介紹第三方套件,讓開發更快速、更彈性。