SwiftUI 數據綁定與視圖更新(@State、@ObservedObject、@EnvironmentObject)

引言

在 SwiftUI 中,界面并不是通過手動刷新來更新的,而是由狀態驅動的。當狀態發生變化,SwiftUI 會自動識別哪些視圖需要重繪,從而保持 UI 與數據的一致性。這種聲明式的方式大大簡化了界面開發的流程,但也帶來一個問題:狀態到底該怎么管理,才能讓視圖“正確地”更新?

SwiftUI 提供了多種狀態綁定機制,包括?@State、@ObservedObject?和?@EnvironmentObject。它們雖然都是用來驅動視圖更新,但適用的場景、生命周期、綁定方式卻各不相同。一不小心,可能就會遇到“明明數據變了,界面卻不更新”的尷尬場面。

這篇文章將深入講解 SwiftUI 中的三種主要數據綁定方式,結合具體的使用場景和代碼實例,幫助你理清它們的使用邏輯,掌握最佳實踐,避免常見誤區。無論你是剛接觸 SwiftUI 的新手,還是已經在項目中使用它的開發者,這篇文章都能為你在構建可維護、響應式的界面上提供幫助。

實戰場景:用一個用戶頁面串起三種狀態綁定方式

為了更直觀地理解 SwiftUI 中三種核心狀態綁定方式的使用場景和區別,我們來構建一個實際項目中常見的頁面 ——?MineView,即“個人中心”頁面。

這個頁面的功能需求如下:

  1. 展示用戶信息:包括昵稱與金幣數量。
  2. 金幣顯示開關:點擊“小眼睛”圖標可以切換金幣的隱藏與顯示。
  3. 支持頁面跳轉:例如跳轉到設置頁或其他模塊。

針對這些需求,我們分別會用到:

  1. @State:用于控制金幣是否顯示,這是一個純粹的視圖內部狀態
  2. @ObservedObject:用于監聽用戶數據模型?PHUserHelper?中的金幣和昵稱變化,這是一個綁定外部可觀察對象的狀態
  3. @EnvironmentObject:用于全局路由控制,通過?RouterHelper?管理跳轉,是一個跨頁面共享的全局狀態

接下來,我們將按功能拆解的順序,依次介紹這三種狀態綁定方式的使用方法與最佳實踐。

1. 管理局部狀態:@State 控制金幣隱藏/顯示

在 SwiftUI 中,@State?是最輕量也是最常用的狀態綁定方式。它適用于視圖自身內部的小范圍狀態管理,比如按鈕選中、輸入框內容、視圖顯隱等場景。

在我們的?MineView?頁面中,用戶可以點擊一個“眼睛”圖標,切換金幣是否可見。這種行為是一個純粹的 UI 控制,不涉及外部數據源,因此非常適合使用?@State?來管理。

import Foundation
import SwiftUIstruct MineView: View {/// 控制金幣是否顯示@State private var showGold = truevar body: some View {HStack(spacing: 12) {Text("金幣:").font(.headline)// 根據狀態展示金幣數量或密文Text(showGold ? "1280" : "****").bold()// 小眼睛按鈕,用于切換狀態Button(action: {showGold.toggle()}) {Image(systemName: showGold ? "eye" : "eye.slash").foregroundColor(.blue)}}.padding().navigationBarBackButtonHidden().toolbar {ToolbarItem(placement: .navigationBarLeading) {Button(action: {}) {Image(systemName: "chevron.left").foregroundColor(.black)}}ToolbarItem(placement: .principal) {Text(LanguageHelper.localizedString(for: "my_title")).font(.headline).foregroundColor(.primary)}}}
}
  • @State?修飾的變量?showGold?是一個?局部狀態,只在當前視圖中使用;
  • 當?showGold?的值發生變化時,SwiftUI 會自動刷新依賴它的 UI(即?Text?和?Image);
  • SwiftUI 中的視圖是值類型,@State?讓這些值類型視圖也擁有“持久狀態”的能力。

場景

是否適合用?@State

控制某個按鈕是否選中

? 是

輸入框的實時文本綁定

? 是

控制一個彈窗是否彈出

? 是

管理整個用戶對象或大型數據結構

? 否,考慮?@ObservedObject

2. 監聽數據變化:@ObservedObject?實時更新用戶信息

當視圖需要響應某個外部對象的屬性變化,比如用戶昵稱或金幣數量,就需要使用?@ObservedObject。

在我們的場景中,用戶信息由一個單例類?PHUserHelper?管理,并持有一個?PHUser?模型。我們希望當用戶的金幣數量或昵稱更新時,MineView?頁面能自動刷新顯示的數據。此時就可以用?@ObservedObject?來監聽這些變化。

模型設計

首先,我們定義一個?PHUser?用戶模型,并通過?@Published?修飾其屬性,確保它們發生變化時會通知觀察者(比如視圖)。

class PHUser: ObservableObject {@Published var nickname: String = "未登錄"@Published var gold: Int = 0
}

然后我們創建一個用戶管理類?PHUserHelper,作為單例提供全局訪問。

class PHUserHelper: ObservableObject {static let shared = PHUserHelper()@Published var user = PHUser()
}

視圖中的使用

struct MineView: View {/// 控制金幣是否顯示@State private var showGold = true/// 監聽用戶管理器@ObservedObject var helper = PHUserHelper.sharedvar body: some View {VStack(alignment: .center, spacing: 12) {// 顯示用戶昵稱Text("歡迎你,\(helper.user.nickname)").font(.title2)HStack(spacing: 12) {Text("金幣:").font(.headline)// 根據狀態展示金幣數量或密文Text(showGold ? "\(helper.user.gold)" : "****").bold()// 小眼睛按鈕,用于切換狀態Button(action: {showGold.toggle()}) {Image(systemName: showGold ? "eye" : "eye.slash").foregroundColor(.blue)}}}.padding().navigationBarBackButtonHidden().toolbar {ToolbarItem(placement: .navigationBarLeading) {Button(action: {}) {Image(systemName: "chevron.left").foregroundColor(.black)}}ToolbarItem(placement: .principal) {Text(LanguageHelper.localizedString(for: "my_title")).font(.headline).foregroundColor(.primary)}}}
}

  • @ObservedObject?修飾的對象必須是遵循了?ObservableObject?協議的類。
  • 被觀察對象的屬性必須使用?@Published?標記,否則屬性改變不會觸發視圖更新。
  • 在視圖中使用對象屬性(如?helper.user.gold)時,SwiftUI 會建立“依賴關系”,從而在屬性變動時自動刷新對應 UI。

3. 跨頁面共享狀態:@EnvironmentObject?實現路由跳轉與全局通信

在 SwiftUI 中,@EnvironmentObject?是一種在多個視圖層級間共享數據的方式,適用于跨頁面的全局狀態管理,比如:用戶信息、App 設置、導航跳轉、主題控制等。

在我們的場景中,MineView?可以跳轉到?EditView,用戶在編輯頁中修改昵稱后返回,主頁面應能自動刷新。為了不手動傳遞路由器對象或用戶對象,我們使用?@EnvironmentObject?注入共享實例。

路由管理器:RouterHelper

需要繼承自ObservableObject,代碼如下:

class RouterHelper: ObservableObject {static let shared = RouterHelper()/// 路徑數組,代表導航棧@Published var path: [PDFRoute] = []private init() {}/// 跳轉到某個路由func push(_ route: PDFRoute) {path.append(route)}/// 返回上一級頁面func pop() {if !path.isEmpty {path.removeLast()}}/// 返回到指定頁/// - Parameter index: 要返回到的頁面索引func popTo(index: Int) {guard index >= 0 && index < path.count else { return }path = Array(path.prefix(upTo: index + 1))}/// 返回首頁,清空路徑func popToRoot() {path.removeAll()}}

路由注入及使用

我們通過?.environmentObject()?將路由管理器注入到mine頁及編輯頁。

                    case .mine:MineView().environmentObject(router)
                    case .edit:// 編輯頁面EditView().environmentObject(RouterHelper.shared)

在?MineView?中使用?@EnvironmentObject?接收這個路由對象,并觸發跳轉:

struct MineView: View {@EnvironmentObject var router: RouterHelper@ObservedObject var user: PHUser@State private var showGold = truevar body: some View {VStack(alignment: .leading, spacing: 16) {HStack {Text("歡迎你,\(helper.user.nickname)")Spacer()Button("編輯昵稱") {router.push(.edit)}}// 金幣顯示部分略...}.padding()}
}

編輯頁:修改昵稱并刷新主視圖

編輯頁不需要通過參數傳值,只需在內部使用?@ObservedObject?和?@EnvironmentObject?即可:

import Foundation
import SwiftUIstruct EditView: View {@EnvironmentObject var router: RouterHelper@ObservedObject var user = PHUserHelper.shared.user@State private var input: String = ""var body: some View {VStack(spacing: 20) {TextField("輸入新昵稱", text: $input).textFieldStyle(RoundedBorderTextFieldStyle())Button("保存") {user.nickname = inputrouter.pop() // 返回上一級頁面}}.padding().onAppear {input = user.nickname}}
}

  • @EnvironmentObject?適合用于整個 App 中的共享對象,如用戶狀態、導航器、設置等;
  • 它無需顯式傳參,SwiftUI 會在視圖樹中查找對應類型的注入對象;
  • 一旦數據變化,所有依賴它的視圖都會自動刷新;
  • 注意必須在上層注入?.environmentObject(...),否則會導致運行時崩潰。

場景

是否適合用?@EnvironmentObject

管理全局導航邏輯

? 是

多個頁面需要訪問同一個用戶對象

? 是

只在當前視圖內部使用的數據

? 否,考慮?@State?或?@ObservedObject

結語

SwiftUI 是一個高度響應式的框架,它的核心思想是數據驅動視圖。只要狀態發生變化,視圖就會自動更新。為了支持這種機制,SwiftUI 提供了多種狀態屬性包裝器,而其中最常見的三種就是我們今天講解的:@State、@ObservedObject、@EnvironmentObject。

通過用戶主頁這一現實場景,我們看到了它們各自的使用姿勢與適用范圍。在實際開發中,理解它們的作用范圍聲明周期管理視圖響應方式,可以幫助我們更高效地構建清晰、可靠、響應式的用戶界面。

三種狀態綁定方式對比表:

特性

@State

@ObservedObject

@EnvironmentObject

生命周期歸屬

當前視圖

外部傳入的可觀察對象

上層注入的共享對象

適用范圍

小范圍內部狀態(局部 UI 控制)

多視圖間共享狀態

跨層級/全局狀態共享

數據變化后視圖刷新

? 自動

? 自動(只刷新使用該屬性的視圖)

? 自動(所有引用該對象的視圖)

聲明時傳入方式

本地初始化

需要從外部?init()?傳入

必須通過?.environmentObject()注入

示例

控制按鈕開關、輸入框文本等

用戶信息、定時器、下載狀態等

路由器、主題管理器、全局配置等

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

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

相關文章

21-Oracle 23 ai-Automatic SQL Plan Management(SPM)

小伙伴們&#xff0c;有沒有遷移數據庫完畢后或是突然某一天在同一個實例上同樣的SQL&#xff0c; 性能不一樣了、業務反饋卡頓、業務超時等各種匪夷所思的現狀。 于是SPM定位開始&#xff0c;OCM考試中SPM必考。 其他的AWR、ASH、SQLHC、SQLT、SQL profile等換作下一個話題…

[Linux] 命令行管理文件

目錄 FHS 文件路徑導航 ls命令 tree命令 stat命令 touch命令 命令行管理文件 mkdir命令 cp命令 mv命令 rm和rmdir命令 軟鏈接 硬鏈接 軟連接硬鏈接區別 shell擴展匹配文件 FHS FHS采用樹形結構組織文件&#xff0c;定義了系統中每個區域的用途、所需要的最小構…

自動化過程中,如何定位一閃而過的toast?

MutationObserver實戰&#xff1a;動態捕獲頁面Toast消息的終極解決方案 一、代碼全景解析 const observer new MutationObserver((mutations) > {// 回調函數主體... });observer.observe(document.body, {childList: true,subtree: true });核心組件解析 組件作用重要…

基于 Three.js 的數字雨波紋效果技術解析

文章目錄 一、基礎環境搭建與 Three.js 引入?二、場景與相機設置?三、后期處理:光暈效果的實現?四、紋理創建:定制雨滴、波紋和水花外觀?五、粒子系統:模擬雨滴下落與交互?1,雨滴粒子系統?2,波紋與水花系統?六、動畫循環與交互響應?本文將深入剖析一段實現該效果的…

聯想拯救者R9000P 網卡 Realtek 8852CE Ubuntu/Mint linux 系統睡眠后,無線網卡失效

聯想拯救者R9000P 網卡型號 Realtek PCle GbE Family Controller Realtek 8852CE WiFi 6E PCI-E NIC 系統版本 Ubuntu 24.04 / mint 22.1 問題現象 rtw89_8852ce&#xff0c;Link is Down&#xff0c;xtal si not ready&#xff0c;mac init fail&#xff0c;xtal si not …

Java詳解LeetCode 熱題 100(26):LeetCode 142. 環形鏈表 II(Linked List Cycle II)詳解

文章目錄 1. 題目描述1.1 鏈表節點定義 2. 理解題目2.1 問題可視化2.2 核心挑戰 3. 解法一&#xff1a;HashSet 標記訪問法3.1 算法思路3.2 Java代碼實現3.3 詳細執行過程演示3.4 執行結果示例3.5 復雜度分析3.6 優缺點分析 4. 解法二&#xff1a;Floyd 快慢指針法&#xff08;…

安寶特科技丨Pixee Medical產品獲FDA認證 AR技術賦能骨科手術智能化

法國醫療科技企業Pixee Medical宣布&#xff0c;其研發的智能骨科手術導航系統 Knee NexSight 解決方案正式通過美國食品藥品監督管理局&#xff08;FDA&#xff09;510(k)認證&#xff0c;標志著增強現實&#xff08;AR&#xff09;技術在醫療領域的商業化應用邁出關鍵一步。 …

操作系統的概念,功能和目標

小懶來了&#xff01; 操作系統學習正式開始&#xff0c;day1是小懶O&#xff01; Using blogs to organize and understand knowledge is a good way, lets learn, operating systems Chapter 1,Lets look at it &#xff08;一&#xff09;預備知識 一.什么是接口 1.假設我…

STM32使用水位傳感器

1.1 介紹&#xff1a; 水位傳感器專為水深檢測而設計&#xff0c;可廣泛用于感應降雨&#xff0c;水位&#xff0c;甚至液體泄漏。當將水位傳感器放入水中時&#xff0c;水位沒過銅線越多模擬值越大&#xff0c;讀取水深傳感器模塊的模擬值&#xff0c;在串口打印出來&#xf…

Spring事務傳播機制有哪些?

導語&#xff1a; Spring事務傳播機制是后端面試中的必考知識點&#xff0c;特別容易出現在“項目細節挖掘”階段。面試官通過它來判斷你是否真正理解事務控制的本質與異常傳播機制。本文將從實戰與源碼角度出發&#xff0c;全面剖析Spring事務傳播機制&#xff0c;幫助你答得有…

相機Camera日志實例分析之一:相機Camx【前置慢動作分辨率切換720P、1080P錄制】單幀流程日志詳解

【關注我&#xff0c;后續持續新增專題博文&#xff0c;謝謝&#xff01;&#xff01;&#xff01;】 上一篇我們講了&#xff1a; 這一篇我們開始講&#xff1a; 目錄 一、場景操作步驟 二、日志基礎關鍵字分級如下 三、場景日志如下&#xff1a; 一、場景操作步驟 1、打…

OpenHarmony標準系統-HDF框架之I2C驅動開發

文章目錄 引言I2C基礎知識概念和特性協議&#xff0c;四種信號組合 I2C調試手段硬件軟件 HDF框架下的I2C設備驅動案例描述驅動Dispatch驅動讀寫 總結 引言 I2C基礎知識 概念和特性 集成電路總線&#xff0c;由串網12C(1C、12C、Inter-Integrated Circuit BUS)行數據線SDA和串…

Ubuntu系統下交叉編譯openssl

一、參考資料 OpenSSL&&libcurl庫的交叉編譯 - hesetone - 博客園 二、準備工作 1. 編譯環境 宿主機&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉編譯器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 設置交叉編譯工具鏈 在交叉編譯之前&#x…

數據庫優化實戰分享:高頻場景下的性能調優技巧與案例解析

在實際開發與生產運維中&#xff0c;數據庫的性能瓶頸往往是影響系統響應速度和用戶體驗的關鍵因素。尤其是在高并發訪問、海量數據處理、復雜查詢邏輯等高頻場景下&#xff0c;數據庫優化不僅僅是“錦上添花”&#xff0c;更是“雪中送炭”。本篇博文將結合實際項目經驗&#…

Python importlib 動態加載

文章目錄 1. importlib 庫 概述2. 導入模塊&#xff08;import_module()&#xff09;2.1. 導入已安裝的模塊2.2. 導入子模塊2.3 通過字符串變量導入模塊 3. 重新加載模塊&#xff08;reload()&#xff09;4. 檢查模塊是否存在&#xff08;find_spec()&#xff09;5. 獲取模塊路…

(1-6-4) Java IO流實現文件的讀取與寫入

目錄 0.前述概要 1. File類 1.1 概述 1.2 File的重要方法 1.3 java.io 1.3.1 四種抽象類 1.3.2 流 1.3.3 其他常用 I/O 流 2. 字節輸入流&#xff08;InputSteam&#xff09; 2.1 關系類圖 2.2 應用實現 3. 字節輸出流&#xff08;OutputStream&#xff09; 3.1 …

【Proteus仿真】【32單片機-A010】步進電機控制系統設計

目錄 一、主要功能 二、使用步驟 三、硬件資源 四、軟件設計 五、實驗現象 聯系作者 一、主要功能 1、LCD顯示當前擋位、方向等&#xff1b; 2、按鍵控制步進電機擋位、方向等。 二、使用步驟 系統運行后&#xff0c;LCD1602顯示當前擋位、方向&#xff1b; 通過按鍵…

DeepSeek-R1-0528-Qwen3-8B為底座微調領域大模型準備:制作領域專用數據集

前言 想要微調領域大模型,數據的準備是必不可少的。然而微調大模型需要的數據極多,這樣花費很多人力和準備。有沒有方便又高效的方法?一下子就可以準備大量的領域專用數據集呢? 制作領域專用數據集 這里制作的數據集格式為使用的aphaca格式的 1.啟動vllm服務 python -m…

WEB3全棧開發——面試專業技能點P6后端框架 / 微服務設計

一、Express Express是國內大部分公司重點問的。我在本文最后&#xff0c;單獨講解了Express框架。 概念介紹 Express 是基于 Node.js 平臺的極簡、靈活且廣泛使用的 Web 應用框架。它提供了一系列強大的功能&#xff0c;用于構建單頁、多頁及混合型的 Web 應用程序和 API 服…

游戲開發中的CI/CD優化案例:知名游戲公司Gearbox使用TeamCity簡化CI/CD流程

案例背景 關于Gearbox&#xff1a; Gearbox 是一家美國電子游戲公司&#xff0c;總部位于德克薩斯州弗里斯科&#xff0c;靠近達拉斯。Gearbox 成立于1999年&#xff0c;推出過多款史上最具代表性的視頻游戲&#xff0c;包括《半衰期》、《戰火兄弟連》以及《無主之地》。 團隊…