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!