SwiftUI學(xué)習(xí)之@ObservableObject 和 @EnvironmentObject

一锋喜、Protocol ObservableObject

protocol ObservableObject : AnyObject
ObservableObject協(xié)議是SwiftUI和Combine框架中的一種機(jī)制搂鲫,
允許對象在狀態(tài)變化前發(fā)出通知。這一機(jī)制對于構(gòu)建響應(yīng)式用戶界面特別有用潜必,因?yàn)樗_保了當(dāng)數(shù)據(jù)模型更新時(shí)靴姿,UI可以立即做出反應(yīng)并更新自身。

默認(rèn)情況下磁滚,遵循ObservableObject協(xié)議的類會自動(dòng)生成一個(gè)名為objectWillChange的發(fā)布者佛吓,這個(gè)發(fā)布者在任何帶有@Published屬性發(fā)生改變之前發(fā)出信號,通知訂閱者即將發(fā)生的更改垂攘。

class Contact: ObservableObject {
    @Published var name: String
    @Published var age: Int


    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }


    func haveBirthday() -> Int {
        age += 1
        return age
    }
}


let john = Contact(name: "John Appleseed", age: 24)
cancellable = john.objectWillChange
    .sink { _ in
        print("\(john.age) will change")
}
print(john.haveBirthday())
// Prints "24 will change"
// Prints "25"

二维雇、@ObservedObject

@ObservedObject是一個(gè)屬性包裝器類型,它訂閱了一個(gè)可觀察對象晒他,并在可觀察對象發(fā)生變化時(shí)使視圖失效吱型,觸發(fā)視圖的重新渲染。

當(dāng)你在SwiftUI中處理數(shù)據(jù)陨仅,特別是當(dāng)你需要一個(gè)視圖響應(yīng)一個(gè)復(fù)雜對象(即ObservableObject)的屬性變化時(shí)津滞,你會使用@ObservedObject屬性包裝器铝侵。這通常發(fā)生在你需要將一個(gè)StateObject的實(shí)例傳遞給子視圖,并希望子視圖能夠?qū)崟r(shí)響應(yīng)這個(gè)對象狀態(tài)的變化触徐。

以下是一個(gè)具體的例子咪鲜,說明了如何定義一個(gè)數(shù)據(jù)模型作為可觀察對象,然后在主視圖中以StateObject的形式實(shí)例化這個(gè)模型锌介,并將這個(gè)實(shí)例作為ObservedObject傳給子視圖:

class DataModel: ObservableObject {
    @Published var name = "Some Name"
    @Published var isEnabled = false
}


struct MyView: View {
    @StateObject private var model = DataModel()


    var body: some View {
        Text(model.name)
        MySubView(model: model)
    }
}


struct MySubView: View {
    @ObservedObject var model: DataModel


    var body: some View {
        Toggle("Enabled", isOn: $model.isEnabled)
    }
}

每當(dāng)可觀察對象的任何已發(fā)布(@Published)屬性發(fā)生變化時(shí)嗜诀,SwiftUI會自動(dòng)更新所有依賴于該對象的視圖。子視圖也可以修改模型的屬性孔祸,就像上述例子中的Toggle那樣隆敢,這些更改會傳播到視圖層級中的其他觀察者。

三崔慧、@StateObject

在SwiftUI中拂蝎,使用StateObject作為引用類型在視圖層級中存儲的單一真實(shí)來源。你可以在App惶室、Scene或View中通過將@StateObject屬性應(yīng)用到屬性聲明上温自,并提供一個(gè)遵循ObservableObject協(xié)議的初始值,來創(chuàng)建一個(gè)狀態(tài)對象皇钞。將狀態(tài)對象聲明為私有(private)可以防止從成員級聯(lián)初始化器(memberwise initializer)設(shè)置它們悼泌,因?yàn)檫@可能與SwiftUI提供的存儲管理沖突。

class DataModel: ObservableObject {
    @Published var name = "Some Name"
    @Published var isEnabled = false
}


struct MyView: View {
    @StateObject private var model = DataModel() // Create the state object.


    var body: some View {
        Text(model.name) // Updates when the data model changes.
        MySubView()
            .environmentObject(model)
    }
}

四夹界、@EnvironmentObject

當(dāng)你在一個(gè)視圖中聲明一個(gè)環(huán)境對象(environment object)時(shí)馆里,意味著這個(gè)視圖及其子視圖將會監(jiān)聽并響應(yīng)任何符合ObservableObject協(xié)議的對象的變化。具體來說可柿,每當(dāng)這個(gè)可觀察對象的屬性發(fā)生變化時(shí)鸠踪,當(dāng)前視圖及其所有依賴于該環(huán)境對象的子視圖都會被標(biāo)記為無效,從而觸發(fā)重新構(gòu)建過程复斥,確保界面能夠反映出最新的狀態(tài)营密。

class UserData: ObservableObject {
    @Published var name = "Some Name"
    @Published var isEnabled = false
}


struct MyApple: App {
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(UserData())
        }
    }
}

    @StateObject var  userData:UserData = UserData()
    var body: some View {
        NavigationView {
            List {
                Toggle(isOn: $userData.showFavoritesOnly) {
                    Text("Favorites only")
                }
                ForEach(userData.landmarks) { landmark in
                    if !userData.showFavoritesOnly || landmark.isFavorite {
                        NavigationLink(destination: LandmarkDetai().environmentObject(self.userData)) {
                            LandmarkRow(landmark: landmark)
                        }
                    }
                }
            }
            .navigationBarTitle(Text("Landmarks"))
        }
    }
}


struct LandmarkDetai: View {
    @EnvironmentObject   private var userData: UserData
    var body: some View {
      
                Button(action: {
                
                    print(self.userData.landmarks[1].name)
                    
                    dismiss()
                    
                })
        }
    }

}

當(dāng)你在一個(gè)視圖中使用.environmentObject(_:)修飾符注冊了一個(gè)環(huán)境對象,這個(gè)對象就會成為該視圖及其所有子視圖環(huán)境的一部分目锭。然后评汰,任何子視圖,無論它在層級結(jié)構(gòu)中的位置有多深痢虹,都可以使用@EnvironmentObject屬性包裝器來訪問這個(gè)對象键俱,就像它是直接嵌入在視圖中的一樣。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末世分,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缀辩,更是在濱河造成了極大的恐慌臭埋,老刑警劉巖踪央,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異瓢阴,居然都是意外死亡畅蹂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門荣恐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來液斜,“玉大人,你說我怎么就攤上這事叠穆∩倨幔” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵硼被,是天一觀的道長示损。 經(jīng)常有香客問我,道長嚷硫,這世上最難降的妖魔是什么检访? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮仔掸,結(jié)果婚禮上脆贵,老公的妹妹穿的比我還像新娘。我一直安慰自己起暮,他們只是感情好卖氨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鞋怀,像睡著了一般双泪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上密似,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天焙矛,我揣著相機(jī)與錄音,去河邊找鬼残腌。 笑死村斟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抛猫。 我是一名探鬼主播蟆盹,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼闺金!你這毒婦竟也來了逾滥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤败匹,失蹤者是張志新(化名)和其女友劉穎寨昙,沒想到半個(gè)月后讥巡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舔哪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年欢顷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捉蚤。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抬驴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缆巧,到底是詐尸還是另有隱情布持,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布盅蝗,位于F島的核電站鳖链,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏墩莫。R本人自食惡果不足惜芙委,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望狂秦。 院中可真熱鬧灌侣,春花似錦、人聲如沸裂问。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽堪簿。三九已至痊乾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間椭更,已是汗流浹背哪审。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留虑瀑,地道東北人湿滓。 一個(gè)月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像舌狗,于是被迫代替她去往敵國和親叽奥。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容