SwiftUI 紀錄-Property Wrapper
6 min readSep 12, 2024
在 SwiftUI 中,屬性包裝器是一種特殊的語法,用於管理 View 的狀態、環境設定以及儲存 App 資料。它們提供了一種簡潔、宣告式的方式來處理這些複雜的問題。我們將深入探討六個常用的屬性包裝器。
- @State
- @Binding
- @ObservedObject
- @Environment
- @EnvironmentObject
- @AppStorage
@State
@State
是管理 View 內部狀態的屬性包裝器,能儲存和自動更新 View 所需的資料。它是 View 私有的,只能在 View 內部存取和修改,有助於保持 View 的獨立性。
應用場景
- 常用於開關狀態、文字輸入
- 本地狀態(Local State):如果變數的狀態僅在該 View 內部需要追蹤和更新,那麼應該使用
@State
。 - 私有狀態(Private State):當該狀態不需要被父 View 或其他 View 訪問時,使用
@State
是適當的選擇。
struct ContentView: View {
@State private var count = 0
var body: some View {
Button("Increment") {
count += 1
}
Text("Count: \\(count)")
}
}
@Binding
@Binding
是在 View 間共享狀態的屬性包裝器,實現子 View 與父 View 的資料交換。
它提供雙向綁定,允許子 View 讀取和修改父 View 傳遞的變數,變更會同步到父 View。
應用場景:
- 在 View 層級間共享狀態
- 雙向綁定(Two-Way Binding):當子 View 需要向父 View 傳遞狀態變化,且父 View 需要反映這些變化時。
- SwiftUI 很多操作的元件都是綁定資料的 Binding 元件,比方 Toggle,TextField,Slider,Sheet 等。
struct ParentView: View {
@State private var sliderValue: Double = 0.5
var body: some View {
VStack {
Text("Slider Value: \\(sliderValue)")
ChildSliderView(value: $sliderValue) // 傳入 Binding
}
.padding()
}
}
struct ChildSliderView: View {
@Binding var value: Double
var body: some View {
Slider(value: $value, in: 0...1)
}
}
@ObservedObject
@ObservedObject
用於監視由其他物件管理的狀態。這些物件通常是遵循ObservableObject
協議的類別,能夠發布狀態的變更。
應用場景:
- 當 View 需要監聽和反應其他地方的狀態變化時,例如從網絡加載資料或監控全局 App 狀態。
class Counter: ObservableObject {
@Published var count = 0 // 被監聽的屬性
}
struct ObservedObjectExampleView: View {
@ObservedObject var counter = Counter()
var body: some View {
VStack {
Text("Count: \\(counter.count)")
Button("Increment") {
counter.count += 1
}
}
.padding()
}
}
@Environment
@Environment
是用於存取全局環境變數的屬性包裝器。它可以讓 View 取得系統提供的設定,例如字體、顏色主題等。
應用場景:
- 根據使用者偏好設定字體大小
@Environment(\\.sizeCategory)
- 根據暗/亮模式設定背景色
@Environment(\\.colorScheme)
- 存取其他系統資訊,如日期
\\.calendar
、語言\\.locale
struct ContentView: View {
@Environment(\\.colorScheme) var colorScheme
var body: some View {
Text("Hello, World!")
.foregroundColor(colorScheme == .dark ? .white : .black)
}
}
@EnvironmentObject
@EnvironmentObject
用於在多個 View 之間共享一個由 ObservableObject
管理的狀態。
應用場景:
- 當需要在多個 View 之間共享狀態,例如使用者設定、全局資料等。
- 適用於需要在父 View 和子 View 間傳遞資料時,特別是在 App 的不同層級的多個 View 之間都需要使用相同的資料。
// 定義一個 ObservableObject
class UserSettings: ObservableObject {
@Published var username: String = "Guest"
}
struct EnvironmentObjectExampleView: View {
@EnvironmentObject var settings: UserSettings // 從環境中獲取 UserSettings 物件
var body: some View {
Text("Hello, \\(settings.username)!")
.padding()
}
}
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
EnvironmentObjectExampleView()
.environmentObject(UserSettings()) // 提供 UserSettings 物件到環境中
}
}
}
@AppStorage
@AppStorage
是用於在 UserDefaults 中儲存和讀取資料的屬性包裝器。它提供了一種簡單的方式來管理 App 的持久性資料。
應用場景:
- 儲存使用者偏好設定
- 在 App 各個 View 間共享資料
- 在 App 更新後維持持久性資料
struct ContentView: View {
@AppStorage("username") private var username = ""
var body: some View {
TextField("Enter username", text: $username)
.textFieldStyle(RoundedBorderTextFieldStyle())
Text("Saved username: \\(username)")
}
}