SwiftUI教程(七)屬性包裝器:State、Binding俗壹、ObservableObject科汗、EnvironmentObject

SwiftUI教程系列文章匯總

本文主要講述SwiftUI中的屬性包裝器,這些包裝器都是用來數據綁定的绷雏,作為視圖的唯一真值來源头滔,四種方式在實現功能上有細微差別。最后會進行總結比較涎显。

主要內容:

  1. State
  2. Binding
  3. ObservableObject
  4. EnvironmentObject

1. @State

SwiftUI管理聲明為state的存儲屬性坤检。當值發(fā)生變化時,SwiftUI會更新視圖層次結構中依賴于該值的部分期吓。使用@State作為存儲在視圖層次結構中的給定值的唯一真值來源早歇。
@State修飾的屬性雖然是存儲屬性,但是我們可以進行讀寫操作讨勤。

父視圖和子視圖進行傳遞該屬性只能是值傳遞箭跳。

需要在屬性名稱前加上一個美元符號$來獲得這個值。因為它是投影屬性

代碼:

struct ContentView: View {
    @State private var str: String = ""
    var body: some View {
        VStack {
            TextField("Placeholder", text: $str)
            Text("\(str)")
        }
    }
}

說明:

  1. 在str上設置了@State修飾潭千,那么我在文本輸入框中輸入的數據谱姓,就會傳入到str中
  2. 同時str又綁定在文本視圖上,所以會將文本輸入框輸入的文本顯示到文本視圖上
  3. 這就是數據綁定的快捷實現刨晴。

注意:

  • 不要在視圖層次結構中實例化視圖的位置初始化視圖的狀態(tài)屬性屉来,因為這可能與SwiftUI提供的存儲管理沖突路翻。
  • 為了避免這種情況,總是將state聲明為private奶躯,并將其放在視圖層次結構中需要訪問該值的最高視圖中帚桩。
  • 然后與任何也需要訪問的子視圖共享該狀態(tài),可以直接用于只讀訪問嘹黔,也可以作為讀寫訪問的綁定账嚎。

2. Binding

@State修飾的屬性是值傳遞,因此在父視圖和子視圖之間傳遞屬性時儡蔓。子視圖針對屬性的修改無法傳遞到父視圖上郭蕉。

Binding修飾后會將屬性會變?yōu)橐粋€引用類型,視圖之間的傳遞從值傳遞變?yōu)榱艘脗鬟f喂江,將父視圖和子視圖的屬性關聯起來召锈。這樣子視圖針對屬性的修改,會傳遞到父視圖上获询。

需要在屬性名稱前加上一個美元符號$來獲得這個值涨岁。因為它是投影屬性

下面代碼在主視圖上添加一個BtnView視圖,視圖上添加一個按鈕吉嚣,按鈕點擊后修改isShowText變量梢薪。這里的變量通過傳入參數與主視圖的isShowText進行綁定。綁定到主視圖的isShowText變量上尝哆。主視圖的變量用來決定文本視圖的隱藏和顯示秉撇。

代碼:

struct BtnView: View {
    @Binding var isShowText: Bool
    
    var body: some View {
        Button {
            isShowText.toggle()
        } label: {
            Text("點擊")
        }

    }
}

struct ContentView: View {
    @State private var isShowText: Bool = true
    var body: some View {
        VStack {
            if(isShowText) {
                Text("點擊后會被隱藏")
            } else {
                Text("點擊后會被顯示").hidden()
            }
            BtnView(isShowText: $isShowText)
        }
    }
}

說明:

  1. 按鈕在BtnView視圖中,并且通過點擊秋泄,修改isShowText的值琐馆。
  2. 將BtnView視圖添加到ContentView上作為它的子視圖。并且傳入isShowText恒序。
  3. 此時的傳值是指針傳遞瘦麸,會將點擊后的屬性值傳遞到父視圖上。
  4. 父視圖拿到后也作用在自己的屬性歧胁,因此他的文本視圖會依據該屬性而隱藏或顯示
  5. 如果將@Binding改為@State瞎暑,會發(fā)現點擊后不起作用。這是因為值傳遞子視圖的更改不會反映到父視圖上

3. @ObservableObject

對實例進行監(jiān)聽与帆,其用處和@State非常相似了赌,只不過必須是對象,而且這個被監(jiān)聽的對象可以被多個視圖使用玄糟。需要注意用法

class DelayedUpdater: ObservableObject {
    @Published var value = 0
    init() {
        for i in 1...10 {
            DispatchQueue.main.asyncAfter(deadline: .now() + Double(i)) {
                self.value += 1
            }
        }
    }
}

struct ContentView: View {
    @ObservedObject var updater = DelayedUpdater()
    var body: some View {
        VStack {
            Text("\(updater.value)").padding()
        }
    }
}

說明:

  1. 綁定的數據是一個對象勿她。
  2. 被修飾的對象,其類必須遵守ObservableObject協議
  3. 此時這個類中被@Published修飾的屬性都會被綁定
  4. 使用@ObservedObject修飾這個對象阵翎,綁定這個對象逢并。
  5. 被@Published修飾的屬性發(fā)生改變時之剧,SwiftUI就會進行更新。
  6. 這里當value值會隨著時間發(fā)生改變砍聊。所以updater對象也會發(fā)生改變背稼。此時文本視圖的內容就會不斷更新。

4. @EnvironmentObject

在多視圖中玻蝌,為了避免數據的無效傳遞蟹肘,可以直接將數據放到環(huán)境中,供多個視圖進行使用俯树。

struct EnvView: View {
    @EnvironmentObject var updater: DelayedUpdater
    
    var body: some View {
        Text("\(updater.value)")
    }
}

struct BtnvView: View {
    @EnvironmentObject var updater: DelayedUpdater
    
    var body: some View {
        Text("\(updater.value)")
    }
}
struct ContentView: View {
    let updater = DelayedUpdater()
    var body: some View {
        VStack {
            EnvView().environmentObject(updater)
            BtnvView().environmentObject(updater)
        }
    }
}

說明:

  • 給屬性添加@EnvironmentObject修改帘腹,就將其放到了環(huán)境中。
  • 其他視圖中想要獲取該屬性许饿,可以通過.environmentObject從環(huán)境中獲取阳欲。
  • 可以看到分別將EnvView和BtnvView的屬性分別放到了環(huán)境中
  • 之后我們ContentView視圖中獲取數據時,可以直接通過環(huán)境獲取陋率。
  • 不需要將數據傳遞到ContentView球化,而是直接通過環(huán)境獲取,這樣避免了無效的數據傳遞瓦糟,更加高效
  • 如果是在多層級視圖之間進行傳遞筒愚,會有更明顯的效果。

5. 總結

  • @State將屬性和視圖進行綁定狸页,是唯一真實數據源。子視圖和父視圖之間是值傳遞
  • @Binding在子視圖和父視圖之間是指針傳遞
  • @ObservableObject只能監(jiān)聽對象扯再,并且可以在多個視圖中監(jiān)聽
  • @EnvironmentObject將數據放到環(huán)境中芍耘,更適用在多視圖中
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市熄阻,隨后出現的幾起案子斋竞,更是在濱河造成了極大的恐慌,老刑警劉巖秃殉,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坝初,死亡現場離奇詭異,居然都是意外死亡钾军,警方通過查閱死者的電腦和手機鳄袍,發(fā)現死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吏恭,“玉大人拗小,你說我怎么就攤上這事∮:撸” “怎么了哀九?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵剿配,是天一觀的道長。 經常有香客問我阅束,道長呼胚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任息裸,我火速辦了婚禮蝇更,結果婚禮上,老公的妹妹穿的比我還像新娘界牡。我一直安慰自己簿寂,他們只是感情好,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布宿亡。 她就那樣靜靜地躺著常遂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挽荠。 梳的紋絲不亂的頭發(fā)上克胳,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機與錄音圈匆,去河邊找鬼漠另。 笑死,一個胖子當著我的面吹牛跃赚,可吹牛的內容都是我干的笆搓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼纬傲,長吁一口氣:“原來是場噩夢啊……” “哼满败!你這毒婦竟也來了?” 一聲冷哼從身側響起叹括,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤算墨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后汁雷,有當地人在樹林里發(fā)現了一具尸體净嘀,經...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年侠讯,在試婚紗的時候發(fā)現自己被綠了挖藏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡厢漩,死狀恐怖熬苍,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤柴底,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布婿脸,位于F島的核電站,受9級特大地震影響柄驻,放射性物質發(fā)生泄漏狐树。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一鸿脓、第九天 我趴在偏房一處隱蔽的房頂上張望抑钟。 院中可真熱鬧,春花似錦野哭、人聲如沸在塔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛔溃。三九已至,卻和暖如春篱蝇,著一層夾襖步出監(jiān)牢的瞬間贺待,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工零截, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留麸塞,地道東北人。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓涧衙,卻偏偏與公主長得像哪工,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子弧哎,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內容