SwiftUI之狀態管理全解析

文章目錄

    • 引言
    • 一、`@State`
      • 1.1 基本概念
      • 1.2 初始化與默認值
      • 1.3 注意事項
    • 二、`@Binding`
      • 2.1 基本概念
      • 2.2 初始化與使用
      • 2.3 注意事項
    • 三、`@ObservedObject`
      • 3.1 基本概念
      • 3.2 初始化與使用
      • 3.3 注意事項
    • 四、`@EnvironmentObject`
      • 4.1 基本概念
      • 4.2 初始化與使用
      • 4.3 注意事項
    • 五、`@StateObject`
      • 5.1 基本概念
      • 5.2 初始化與使用
      • 5.3 注意事項
    • 六、@ObservedObject、@StateObject、@EnvironmentObject區別及使用場景
      • 6.1 區別
        • 6.1.1 對象創建和所有權
        • 6.1.2 生命周期管理
        • 6.1.3 數據傳遞方式
      • 6.2 使用場景
        • 6.2.1 `@ObservedObject`
        • 6.2.2 `@StateObject`
        • 6.2.3 `@EnvironmentObject`
    • 七、綜合案例
      • 7.1 電商購物案例
      • 7.2 代碼解釋
        • 7.2.1 數據模型
        • 7.2.2 購物車視圖模型(`ShoppingCartViewModel`)
        • 7.2.3 商品單元格視圖(`ProductCell`)
        • 7.2.4 商品列表視圖(`ProductListView`)
        • 7.2.5 購物車視圖(`CartView`)
        • 7.2.6 主視圖(`MainView`)
    • 八、小結

引言

在 SwiftUI 中,狀態管理是構建交互式和動態用戶界面的核心。狀態代表著應用程序的數據,當這些數據發生變化時,SwiftUI 會自動更新與之關聯的視圖,以反映最新的狀態。本文將詳細介紹 SwiftUI 中幾種常見的狀態管理方式,包括 @State@Binding@ObservedObject@EnvironmentObject@StateObject,并探討它們的使用場景、初始化、默認值設置以及注意事項。

一、@State

1.1 基本概念

@State 是 SwiftUI 中用于管理視圖私有狀態的屬性包裝器。它通常用于存儲簡單的值,如布爾值、整數、字符串等,并且只能在結構體視圖中使用。當 @State 變量的值發生變化時,SwiftUI 會重新計算并更新依賴于該變量的視圖部分。

1.2 初始化與默認值

@State 變量必須在聲明時進行初始化,因為它代表著視圖的初始狀態。可以為其提供一個默認值,這個默認值將作為視圖首次顯示時的狀態。

import SwiftUIstruct StateExampleView: View {// 初始化 @State 變量并設置默認值@State private var isFavorite = falsevar body: some View {Button(action: {self.isFavorite.toggle()}) {Text(isFavorite ? "已收藏" : "收藏")}}
}

在上述代碼中,isFavorite 是一個 @State 變量,初始值為 false。當按鈕被點擊時,isFavorite 的值會取反,視圖會相應地更新顯示內容。
在這里插入圖片描述

1.3 注意事項

  • 私有性@State 變量應該是私有的,因為它是視圖的內部狀態,不應該被外部視圖直接訪問或修改。
  • 值類型@State 通常用于存儲值類型(如結構體、枚舉),因為值類型的賦值會創建一個新的副本,這有助于 SwiftUI 檢測狀態的變化。
  • 視圖重建:當 @State 變量的值發生變化時,SwiftUI 會重新計算整個視圖的 body 屬性,因此應避免在 body 中執行昂貴的操作。

二、@Binding

2.1 基本概念

@Binding 用于在不同視圖之間共享狀態,實現雙向數據綁定。它允許一個視圖修改另一個視圖的狀態,通常用于將父視圖的 @State 變量傳遞給子視圖。

2.2 初始化與使用

@Binding 變量不能直接初始化,它必須通過外部傳遞的 Binding 實例進行賦值。通常在父視圖中使用 $ 符號將 @State 變量轉換為 Binding 實例,并傳遞給子視圖。

import SwiftUI// 子視圖
struct TextFieldView: View {@Binding var text: Stringvar body: some View {TextField("輸入文本", text: $text)}
}// 父視圖
struct BindingExampleView: View {@State private var inputText = ""var body: some View {VStack {// 將 @State 變量轉換為 Binding 并傳遞給子視圖TextFieldView(text: $inputText)Text("你輸入的文本是: \(inputText)")}}
}

在上述代碼中,TextFieldView 接收一個 @Binding 變量 text,并將其綁定到 TextField 上。父視圖 BindingExampleView 將自己的 @State 變量 inputText 通過 $ 符號轉換為 Binding 實例傳遞給子視圖。當用戶在 TextField 中輸入文本時,父視圖中的 inputText 會相應更新。
在這里插入圖片描述

2.3 注意事項

  • 依賴外部狀態@Binding 變量依賴于外部傳遞的 Binding 實例,因此必須確保在使用之前已經正確初始化。
  • 數據一致性:由于 @Binding 實現了雙向數據綁定,任何對 @Binding 變量的修改都會反映到原始的 @State 變量上,需要注意數據的一致性和正確性。

三、@ObservedObject

3.1 基本概念

@ObservedObject 用于觀察符合 ObservableObject 協議的對象。當被觀察對象的 @Published 屬性發生變化時,SwiftUI 會自動更新關聯的視圖。@ObservedObject 通常用于管理復雜的狀態邏輯,將狀態和業務邏輯封裝在一個獨立的對象中。

3.2 初始化與使用

@ObservedObject 變量可以在視圖中直接初始化,也可以通過外部傳遞。被觀察的對象必須符合 ObservableObject 協議,并且需要使用 @Published 標記需要觀察的屬性。

import SwiftUI
import Combine// 定義一個符合 ObservableObject 協議的類
class CounterViewModel: ObservableObject {// 使用 @Published 標記需要觀察的屬性@Published var count = 0func increment() {count += 1}
}struct ObservedObjectExampleView: View {// 初始化 @ObservedObject 變量@ObservedObject private var viewModel = CounterViewModel()var body: some View {VStack {Text("計數: \(viewModel.count)")Button(action: {self.viewModel.increment()}) {Text("增加計數")}}}
}

在上述代碼中,CounterViewModel 是一個符合 ObservableObject 協議的類,包含一個 @Published 屬性 countObservedObjectExampleView 使用 @ObservedObject 觀察 CounterViewModel 的實例。當點擊按鈕調用 viewModel.increment() 方法時,count 屬性的值會改變,SwiftUI 會自動更新 Text 視圖以顯示新的計數。
在這里插入圖片描述

3.3 注意事項

  • 對象生命周期@ObservedObject 不會管理被觀察對象的生命周期,因此需要確保對象在視圖使用期間不會被銷毀。通常在父視圖中創建對象并傳遞給子視圖,或者使用 @StateObject 來管理對象的生命周期。
  • 線程安全@Published 屬性的修改應該在主線程上進行,因為 SwiftUI 的視圖更新是在主線程上執行的。如果在后臺線程中修改 @Published 屬性,可能會導致視圖更新不一致或崩潰。

四、@EnvironmentObject

4.1 基本概念

@EnvironmentObject 用于在整個視圖層次結構中共享一個 ObservableObject 實例。與 @ObservedObject 不同的是,@EnvironmentObject 可以在多個視圖中輕松訪問同一個狀態對象,而不需要通過層層傳遞參數。

4.2 初始化與使用

@EnvironmentObject 變量不需要在視圖中初始化,它會從視圖環境中獲取共享的 ObservableObject 實例。在父視圖中,需要使用 environmentObject 修飾符將 ObservableObject 實例注入到視圖環境中。

import SwiftUI
import Combine

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/71159.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/71159.shtml
英文地址,請注明出處:http://en.pswp.cn/web/71159.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Redis 高可用性:如何讓你的緩存一直在線,穩定運行?

🎯 引言:Redis的高可用性為啥這么重要? 在現代高可用系統中,Redis 是一款不可或缺的分布式緩存與數據庫系統。無論是提升訪問速度,還是實現數據的高效持久化,Redis 都能輕松搞定。可是,當你把 …

面試題:說一下你對DDD的了解?

面試題:說一下你對DDD的了解? 在面試中,關于 DDD(領域驅動設計,Domain-Driven Design) 的問題是一個常見的技術考察點。DDD 是一種軟件設計方法論,旨在通過深入理解業務領域來構建復雜的軟件系統。以下是一個清晰、詳細的回答模板,幫助你在面試中脫穎而出: DDD 的定義…

Redis---緩存穿透,雪崩,擊穿

文章目錄 緩存穿透什么是緩存穿透?緩存穿透情況的處理流程是怎樣的?緩存穿透的解決辦法緩存無效 key布隆過濾器 緩存雪崩什么是緩存雪崩?緩存雪崩的解決辦法 緩存擊穿什么是緩存擊穿?緩存擊穿的解決辦法 區別對比 在如今的開發中&…

Android Logcat 高效調試指南

工具概覽 Logcat 是 Android SDK 提供的命令行日志工具&#xff0c;支持靈活過濾、格式定制和實時監控&#xff0c;官方文檔詳見 Android Developer。 基礎用法 命令格式 [adb] logcat [<option>] ... [<filter-spec>] ... 執行方式 直接調用&#xff08;通過ADB守…

【定昌Linux系統】部署了java程序,設置開啟啟動

將代碼上傳到相應的目錄&#xff0c;并且配置了一個.sh的啟動腳本文件 文件內容&#xff1a; #!/bin/bash# 指定JAR文件的路徑&#xff08;如果JAR文件在當前目錄&#xff0c;可以直接使用文件名&#xff09; JAR_FILE"/usr/local/java/xs_luruan_client/lib/xs_luruan_…

Java 8 中,可以使用 Stream API 和 Comparator 對 List 按照元素對象的時間字段進行倒序排序

文章目錄 引言I 示例對象II List 按時間字段倒序排序: 使用 `Stream` 和 `Comparator` 排序方法 1:使用 `Comparator.comparing`方法 2:使用 `Comparator.reversed`方法 3:自定義 `Comparator`輸出結果III 注意事項**時間字段類型**:**空值處理**:IV 總結引言 案例:在線用…

jvm內存模型,類加載機制,GC算法,垃圾回收器,jvm線上調優等常見的面試題及答案

JVM內存模型 JVM內存模型包括哪些區域 答案&#xff1a;JVM內存模型主要包括以下區域&#xff1a; 程序計數器&#xff1a;是一塊較小的內存空間&#xff0c;它可以看作是當前線程所執行的字節碼的行號指示器&#xff0c;用于記錄正在執行的虛擬機字節碼指令的地址。Java虛擬機…

git clone的時候出現出現error

報錯如下&#xff1a; Collecting githttps://github.com/haotian-liu/LLaVA.git Cloning https://github.com/haotian-liu/LLaVA.git to /tmp/pip-req-build-360q6tt1 Running command git clone --filterblob:none --quiet https://github.com/haotian-liu/LLaVA.git /t…

Minio搭建并在SpringBoot中使用完成用戶頭像的上傳

Minio使用搭建并上傳用戶頭像到服務器操作,學習筆記 Minio介紹 minio官網 MinIO是一個開源的分布式對象存儲服務器&#xff0c;支持S3協議并且可以在多節點上實現數據的高可用和容錯。它采用Go語言開發&#xff0c;擁有輕量級、高性能、易部署等特點&#xff0c;并且可以自由…

vue3中ref和reactive響應式數據、ref模板引用(組合式和選項式區別)、組件ref的使用

目錄 Ⅰ.ref 1.基本用法&#xff1a;ref響應式數據 2.ref模板引用 3.ref在v-for中的模板引用 ?4.ref在組件上使用 ?5.TS中ref數據標注類型 Ⅱ.reactive 1.基本用法&#xff1a;reactive響應式數據 2.TS中reactive標注類型 Ⅲ.ref和reactive的使用場景和區別 Ⅳ.小結…

javascript實現雪花飄落效果

本文實現雪花飄落效果的 JavaScript 網頁設計案例&#xff0c;代碼實現如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, init…

項目準備(flask+pyhon+MachineLearning)- 3

目錄 1.商品信息 2. 商品銷售預測 2.1 機器學習 2.2 預測功能 3. 模型評估 1.商品信息 app.route(/products) def products():"""商品分析頁面"""data load_data()# 計算當前期間和上期間current_period data[data[成交時間] > data[成…

FPGA開發,使用Deepseek V3還是R1(3):系統級與RTL級

以下都是Deepseek生成的答案 FPGA開發&#xff0c;使用Deepseek V3還是R1&#xff08;1&#xff09;&#xff1a;應用場景 FPGA開發&#xff0c;使用Deepseek V3還是R1&#xff08;2&#xff09;&#xff1a;V3和R1的區別 FPGA開發&#xff0c;使用Deepseek V3還是R1&#x…

實現 Leaflet 多類型點位標記與聚合功能的實戰經驗分享

在現代的地理信息系統&#xff08;GIS&#xff09;應用中&#xff0c;地圖功能是不可或缺的一部分。無論是展示商業網點、旅游景點還是公共服務設施&#xff0c;地圖都能以直觀的方式呈現數據。然而&#xff0c;當數據量較大時&#xff0c;地圖上可能會出現大量的標記點&#x…

企微審批中MySQL字段TEXT類型被截斷的排查與修復實踐

在MySQL中&#xff0c;TEXT類型字段常用于存儲較大的文本數據&#xff0c;但在一些應用場景中&#xff0c;當文本內容較大時&#xff0c;TEXT類型字段可能無法滿足需求&#xff0c;導致數據截斷或插入失敗。為了避免這種問題&#xff0c;了解不同文本類型&#xff08;如TEXT、M…

【常見BUG】Spring Boot 和 Springfox(Swagger)版本兼容問題

???歡迎來到我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學習,不斷總結,共同進步,活到老學到老…

HTTP 協議的發展歷程:從 HTTP/1.0 到 HTTP/2.0

HTTP 協議的發展歷程&#xff1a;從 HTTP/1.0 到 HTTP/2.0 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本傳輸協議&#xff09;是 Web 的基礎協議&#xff0c;用于客戶端和服務器之間的通信。從 HTTP/1.0 到 HTTP/2.0&#xff0c;HTTP 協議經歷了多次重大改…

apload-lab打靶場

1.提示顯示所以關閉js 上傳<?php phpinfo(); ?>的png形式 抓包&#xff0c;將png改為php 然后放包上傳成功 2.提示說檢查數據類型 抓包 將數據類型改成 image/jpeg 上傳成功 3.提示 可以用phtml&#xff0c;php5&#xff0c;php3 4.先上傳.htaccess文件&#xff0…

金融支付行業技術側重點

1. 合規問題 第三方支付系統的平穩運營&#xff0c;嚴格遵循《非銀行支付機構監督管理條例》的各項條款是基礎與前提&#xff0c;其中第十八條的規定堪稱重中之重&#xff0c;是支付機構必須牢牢把握的關鍵準則。 第十八條明確指出&#xff0c;非銀行支付機構需構建起必要且獨…

Cherry Studio + 火山引擎 構建個人AI智能知識庫

&#x1f349;在信息化時代&#xff0c;個人知識庫的構建對于提高工作效率、知識管理和信息提取尤為重要。尤其是當這些知識庫能結合人工智能來智能化地整理、分類和管理數據時&#xff0c;效果更為顯著。我最近嘗試通過 Cherry Studio 和 火山引擎 來搭建個人智能知識庫&#…