SwiftUI中的@StateObject和@ObservedObject屬性包裝器指示視圖更新以響應被觀察對象的變化。雖然這兩個屬性包裝器看起來很相似,但在使用SwiftUI構建應用程序時,有一個關鍵的區別需要理解。
兩個屬性包裝器都要求對象符合ObservableObject協議。這個協議表明在對象改變之前有發布者(@Published變量)通知SwiftUI觸發視圖的重繪。
@StateObject的介紹和使用
@StateObject屬性包裝器與其他屬性包裝器不同,@StateObject負責創建和管理包裝對象的生命周期,與@StateObject相關聯的對象在擁有它的視圖的生命周期內持續存在。
在一下兩種情況下,應該使用@StateObject屬性包裝器:
- 初始化一次
- 由視圖擁有的屬性
初始化一次:當由于外部數據更改或重繪操作而重新計算繪制視圖主體時,用@StateObject包裝的屬性不受影響。
屬于視圖:數據的生命周期與視圖的生命周期相關聯。一旦擁有數據的視圖被釋放,數據就會被釋放。
在使用的時候也是比較簡單的,如下:
import SwiftUIstruct VideosView: View {@StateObject private var viewModel = VideoViewModel()var body: some View {List(viewModel.notes, id: \.self) { video inText(video.title)}}
}final class VideoViewModel: ObservableObject {@Published private(set) var videos: [Video] = []
}
@StateObject屬性包裝器包裝后的對象只初始化一次,并在視圖更新期間持續存在。不過@StateObject屬性包裝器只能與引用類型一起使用,因為只有引用類型才能符合ObservableObject協議。
@ObservedObject的介紹和使用
上面了解了@StateObject屬性包裝器在擁有和管理SwiftUI視圖中的數據方面起著重要的作用。不過,并不是每一塊數據都需要或應該由顯示它的視圖擁有。這就是@ObservedObject屬性包裝器發揮作用的地方。與@StateObject不同的是,@ObservedObject被設計成在不獲取所有權的情況下觀察和響應引用類型的變化。
@ObservedObject并不擁有或管理它所觀察對象的生命周期。它只是監聽observable對象中的變化,并觸發視圖的更新。
如果數據是外部的,則選擇@ObservedObject屬性包裝器。
如果視圖需要顯示由外部源(如父視圖或共享數據存儲)擁有和管理的數據,則選擇@ObservedObject屬性包裝器。
使用的時候不需要初始化viewModel,而是由外部傳入。
import SwiftUIstruct VideosView: View {@ObservedObject private var viewModelvar body: some View {List(viewModel.notes, id: \.self) { video inText(video.title)}}
}final class VideoViewModel: ObservableObject {@Published private(set) var videos: [Video] = []
}
使用@ObservedObject而不是@StateObject,因為視圖不會創建和管理VideoViewModel。當視圖被釋放時,VideoViewModel不應該被釋放。
如果發生外部數據更改,@ObservedObject屬性包裝器允許視圖更新其主體。它使得在視圖之間共享數據變得更加容易。與@StateObject不同,ObservedObject并不管理它所觀察對象的生命周期,所以你需要確保對象的生命周期是在應用的其他地方管理的。
總結
@StateObject和@ObservedObject有相似的特性,但是它們在SwiftUI如何管理它們的生命周期方面有所不同。當當前視圖創建觀察對象時,使用@StateObject屬性包裝器確保結果一致。當注入一個被觀察對象作為依賴時,使用@ObservedObject。