SwiftUI 紀錄-Property Wrapper

Zhi-Hong Lin
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)")
}
}

--

--

No responses yet