Terjemahan artikel disiapkan khusus untuk siswa kursus “Pengembang iOS. Kursus Lanjutan v 2.0. "
Minggu lalu kami memulai serangkaian 
posting baru tentang kerangka kerja SwiftUI. Hari ini saya ingin melanjutkan topik ini dengan berbicara tentang 
Pembungkus Properti di SwiftUI. SwiftUI menyediakan pembungkus untuk 
@State , 
@Binding , 
@ObservedObject , 
@EnvironmentObject , dan 
@Environment . Jadi, mari kita coba memahami perbedaan antara mereka dan kapan, mengapa dan mana yang harus kita gunakan. 
Pembungkus properti
Pembungkus Properti (selanjutnya 
disebut "pembungkus properti") dijelaskan dalam 
SE-0258 . Ide utamanya adalah untuk membungkus properti dengan logika, yang dapat diekstraksi ke dalam struktur terpisah untuk digunakan kembali dalam basis kode.
@State adalah pembungkus yang bisa kita gunakan untuk menunjukkan status 
View . SwiftUI akan menyimpannya dalam memori internal khusus di luar struktur 
View . Hanya 
View ditautkan yang dapat mengaksesnya. Ketika nilai properti 
@State berubah, SwiftUI membangun kembali 
View to account untuk perubahan status. Ini adalah contoh sederhana.
 struct ProductsView: View { let products: [Product] @State private var showFavorited: Bool = false var body: some View { List { Button( action: { self.showFavorited.toggle() }, label: { Text("Change filter") } ) ForEach(products) { product in if !self.showFavorited || product.isFavorited { Text(product.title) } } } } } 
Pada contoh di atas, kami memiliki layar sederhana dengan tombol dan daftar produk. Segera setelah kami mengklik tombol, itu mengubah nilai properti negara, dan SwiftUI membangun kembali 
View .
@Binding
@Binding menyediakan akses referensi untuk tipe nilai. Terkadang kita perlu membuat keadaan 
View kita dapat diakses oleh anak-anaknya. Tetapi kita tidak bisa hanya mengambil dan meneruskan nilai ini, karena ini adalah tipe nilai, dan Swift akan meneruskan salinan nilai ini. Di sinilah pembungkus properti 
@Binding datang untuk menyelamatkan.
 struct FilterView: View { @Binding var showFavorited: Bool var body: some View { Toggle(isOn: $showFavorited) { Text("Change filter") } } } struct ProductsView: View { let products: [Product] @State private var showFavorited: Bool = false var body: some View { List { FilterView(showFavorited: $showFavorited) ForEach(products) { product in if !self.showFavorited || product.isFavorited { Text(product.title) } } } } } 
Kami menggunakan 
@Binding untuk menandai properti 
showFavorited di dalam 
FilterView . Kami juga menggunakan 
$ karakter khusus untuk melewati tautan jangkar, karena tanpa 
$ Swift itu akan melewati salinan nilai alih-alih melewati tautan jangkar itu sendiri. 
FilterView dapat membaca dan menulis nilai properti 
showFavorited di 
ProductsView , tetapi tidak dapat melacak perubahan menggunakan pengikatan ini. Segera setelah 
FilterView mengubah nilai properti showFavorited, SwiftUI membuat ulang 
ProductsView dan 
FilterView sebagai anaknya.
@ObservedObject
@ObservedObject bekerja mirip dengan 
@State , tetapi perbedaan utamanya adalah bahwa kita dapat membaginya di antara beberapa 
View independen yang dapat berlangganan dan menonton perubahan pada objek ini, dan segera setelah perubahan muncul, 
SwiftUI membangun kembali semua tampilan yang terkait dengan objek ini. . Mari kita lihat sebuah contoh.
 import Combine final class PodcastPlayer: ObservableObject { @Published private(set) var isPlaying: Bool = false func play() { isPlaying = true } func pause() { isPlaying = false } } 
Di sini kita memiliki kelas 
PodcastPlayer , di mana layar aplikasi kita berbagi di antara mereka sendiri. Setiap layar harus menampilkan tombol jeda mengambang ketika aplikasi memutar episode podcast. 
SwiftUI melacak perubahan pada 
ObservableObject menggunakan pembungkus 
@Published , dan segera setelah properti ditandai sebagai perubahan 
SwiftUI , 
SwiftUI membangun kembali semua 
SwiftUI terkait dengan 
PodcastPlayer ini. Di sini kita menggunakan pembungkus 
@ObservedObject untuk mengikat 
EpisodesView kita ke kelas 
PodcastPlayer struct EpisodesView: View { @ObservedObject var player: PodcastPlayer let episodes: [Episode] var body: some View { List { Button( action: { if self.player.isPlaying { self.player.pause() } else { self.player.play() } }, label: { Text(player.isPlaying ? "Pause": "Play") } ) ForEach(episodes) { episode in Text(episode.title) } } } } 
@EnvironmentObject
Alih-alih meneruskan 
ObservableObject melalui metode init dari 
View kita, kita dapat secara implisit menanamkannya dalam 
Environment hierarki 
View kita. Dengan melakukan ini, kami memungkinkan semua pandangan anak-anak dari 
Environment saat ini untuk mengakses objek yang 
ObservableObject ini.
 class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { let window = UIWindow(frame: UIScreen.main.bounds) let episodes = [ Episode(id: 1, title: "First episode"), Episode(id: 2, title: "Second episode") ] let player = PodcastPlayer() window.rootViewController = UIHostingController( rootView: EpisodesView(episodes: episodes) .environmentObject(player) ) self.window = window window.makeKeyAndVisible() } } struct EpisodesView: View { @EnvironmentObject var player: PodcastPlayer let episodes: [Episode] var body: some View { List { Button( action: { if self.player.isPlaying { self.player.pause() } else { self.player.play() } }, label: { Text(player.isPlaying ? "Pause": "Play") } ) ForEach(episodes) { episode in Text(episode.title) } } } } 
Seperti yang Anda lihat, kami harus melewati 
PodcastPlayer melalui pengubah 
environmentObject dari 
View kami. Dengan melakukan ini, kita dapat dengan mudah mengakses 
PodcastPlayer dengan mendefinisikannya menggunakan pembungkus 
@EnvironmentObject . 
@EnvironmentObject menggunakan fungsi pencarian anggota dinamis untuk menemukan instance kelas 
PodcastPlayer di 
Environment , sehingga Anda tidak perlu meneruskannya melalui metode 
PodcastPlayer EpisodesView . Lingkungan adalah cara yang tepat untuk 
menyuntikkan dependensi ke dalam 
SwiftUI .
@ Lingkungan
Seperti yang kami katakan di bab sebelumnya, kami dapat mentransfer objek khusus ke hierarki 
View Environment di dalam 
SwiftUI . Tetapi 
SwiftUI sudah memiliki 
Environment dipenuhi dengan pengaturan seluruh sistem. Kita dapat dengan mudah mengaksesnya menggunakan pembungkus 
@Environment .
 struct CalendarView: View { @Environment(\.calendar) var calendar: Calendar @Environment(\.locale) var locale: Locale @Environment(\.colorScheme) var colorScheme: ColorScheme var body: some View { return Text(locale.identifier) } } 
Dengan menandai properti kami dengan pembungkus 
@Environment , kami mendapatkan akses dan berlangganan perubahan ke pengaturan seluruh sistem. Segera setelah 
Lokal , 
Kalender atau sistem 
ColorScheme berubah, 
SwiftUI menciptakan 
CalendarView kami.
Kesimpulan
Hari ini kita berbicara tentang Pembungkus Properti yang disediakan oleh 
SwiftUI . 
@State , 
@State , 
@Binding , dan 
@ObservedObject memainkan peran besar dalam pengembangan 
SwiftUI . Terima kasih atas perhatian anda!