Properti body — elemen sentral protokol View di SwiftUI yang menentukan konten apa yang ditampilkan di layar. Menurut Apple Developer Documentation, 2024, body adalah satu-satunya persyaratan wajib protokol View dan mengembalikan tipe yang sesuai dengan protokol yang sama. SwiftUI memanggil body setiap kali terjadi perubahan status untuk membangun dan membandingkan pohon elemen baru.
Poin utama
body — adalah properti komputasi (computed property) yang merupakan satu-satunya persyaratan wajib protokol View. Setiap struktur yang sesuai dengan View harus mengimplementasikan body. Properti ini mengembalikan konten yang ditampilkan SwiftUI di layar — bisa berupa teks, gambar, tombol, wadah dengan elemen bersarang, atau tipe lain apa pun yang sesuai dengan protokol View.
Tanda tangan body selalu tetap: var body: some View { get }. Tipe kembalian — some View (tipe buram), bukan tipe konkret. Ini berarti View yang berbeda dapat mengembalikan tipe konkret yang berbeda di body, tetapi kompiler Swift menetapkan tipe konkret untuk setiap implementasi pada tahap kompilasi.
Menurut WWDC 2022, body adalah titik masuk ke deskripsi deklaratif antarmuka. Berbeda dengan UIKit, di mana Anda secara imperatif membuat dan mengonfigurasi UIView, di SwiftUI Anda secara deklaratif mendeskripsikan apa yang akan ditampilkan, dan SwiftUI sendiri menghitung cara mengimplementasikannya.
body harus berperilaku seperti fungsi murni — dengan data masukan yang sama (properti struktur dan status) harus mengembalikan pohon View yang sama. Jika body bergantung pada status eksternal yang dapat berubah (variabel global, UserDefaults tanpa pembungkus @AppStorage), perilaku menjadi tidak dapat diprediksi, dan SwiftUI dapat menggambar ulang layar secara tidak benar.
Properti komputasi body tidak menyimpan nilai — dihitung setiap kali diakses. Ketika SwiftUI menentukan bahwa status telah berubah, ia membuat ulang struktur View dan membaca nilai baru body untuk mendapatkan pohon elemen terkini yang akan ditampilkan.
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Penghitung: \(count)")
.font(.largeTitle)
Button("Tambah") {
count += 1
}
.padding()
.background(.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
}
}
Dalam contoh ini, body mengembalikan VStack yang berisi Text dan tombol dengan pengubah. Saat tombol ditekan, properti @State count bertambah, SwiftUI membuat ulang struktur CounterView dan memanggil body lagi untuk mendapatkan pohon yang diperbarui dengan nilai Text yang baru.
Pengubah (.font, .padding, .background, .foregroundColor, .cornerRadius) tidak mengubah View asli, tetapi membungkusnya dalam ModifiedContent — tipe baru yang menambahkan modifikasi. Setiap pengubah membuat satu tingkat penyarangan lagi, yang penting untuk dipertimbangkan demi kinerja.
some View dalam tipe kembalian body — bukan hanya konvensi, tetapi persyaratan wajib kompiler. Swift mensyaratkan semua jalur pengembalian di body memiliki tipe konkret yang sama. Tanpa @ViewBuilder Anda tidak dapat mengembalikan Text di satu cabang dan Button di cabang lain — kompiler akan memberikan kesalahan.
struct ConditionalView: View {
var isReady: Bool
@ViewBuilder
var body: some View {
if isReady {
Text("Siap")
.foregroundColor(.green)
} else {
ProgressView()
}
}
}
@ViewBuilder pada body memungkinkan penggunaan logika kondisional (if/else, switch) tanpa kesalahan kompilasi. ViewBuilder secara otomatis membungkus berbagai cabang dalam ConditionalContent — tipe khusus yang menyembunyikan perbedaan tipe konkret. Ini adalah kemampuan kunci untuk membangun antarmuka dinamis.
Tanpa @ViewBuilder kompiler mencoba menyimpulkan tipe tunggal untuk semua jalur pengembalian. Jika tipenya berbeda — terjadi kesalahan. Inilah sebabnya SwiftUI secara implisit menerapkan @ViewBuilder ke body dalam deklarasi View, meskipun dalam kode pengguna anotasi harus ditempatkan secara eksplisit untuk metode dan properti kustom yang mengembalikan beberapa View.
Penggunaan some View alih-alih tipe konkret tidak mengurangi kinerja — kompiler pada tahap kompilasi mengetahui tipe yang tepat dan menghasilkan kode langsung tanpa pengiriman dinamis. AnyView, sebaliknya, menggunakan penghapusan tipe (type erasure) dengan overhead pengemasan ke dalam wadah eksistensial.
body dipanggil oleh SwiftUI dalam tiga skenario utama: saat pertama kali View ditampilkan, saat perubahan @State/@Binding/@ObservedObject/@StateObject, dan saat perubahan View induk yang mengirimkan nilai baru melalui penginisialisasi. SwiftUI juga dapat memanggil body saat perubahan nilai lingkungan (@Environment).
Frekuensi pemanggilan body seharusnya tidak perlu dikhawatirkan — SwiftUI mengoptimalkan penggambaran ulang melalui mekanisme identitas. Setiap View dalam hierarki memiliki pengidentifikasi unik. Jika identitas dan data masukan tidak berubah — body tidak dipanggil, bahkan jika View induk digambar ulang. Ini dicapai melalui perbandingan Equatable dan stabilitas struktur.
struct ParentView: View {
var body: some View {
ChildView(name: "Alice") // Identitas stabil
}
}
struct ChildView: View {
let name: String
var body: some View {
Text("Halo, \(name)!")
}
}
Dalam contoh ini, jika ParentView digambar ulang tetapi mengirimkan nilai name yang sama — ChildView.body tidak dipanggil. SwiftUI membandingkan data masukan struktur dan, jika tidak berubah, melewatkan penggambaran ulang komponen anak. Ini adalah mekanisme diferensiasi View (view differentiation).
Ada beberapa jebakan yang menyebabkan pemanggilan body tidak terduga: penggunaan kelas tanpa ObservableObject, pengiriman penutupan yang dibuat di dalam body (setiap pembuatan penutupan memberikan identitas baru), dan penggunaan EquatableView yang salah. Jika body terlalu sering dipanggil — periksa stabilitas identitas semua komponen anak.
Aturan pertama: body harus minimal. Keluarkan logika kompleks ke properti komputasi terpisah atau metode yang mengembalikan View. Ini meningkatkan keterbacaan dan memungkinkan SwiftUI menentukan dengan lebih tepat bagian hierarki mana yang berubah. Bagilah body besar menjadi subkomponen dengan batas tanggung jawab yang jelas.
Aturan kedua: jangan gunakan body untuk melakukan pekerjaan. Memuat data, bekerja dengan jaringan, menulis ke database — semua ini harus terjadi di luar body, dalam tugas (task), pengubah onChange, atau melalui ObservableObject. body hanya ditujukan untuk deklarasi antarmuka.
Aturan ketiga: gunakan properti EquatableView atau protokol Equatable kustom untuk View, jika perbandingan standar struktur tidak mencukupi. Ini memungkinkan Anda secara eksplisit memberi tahu SwiftUI kapan View anak perlu digambar ulang dan menghindari pemanggilan body yang tidak perlu.
Aturan keempat: jika body berisi perhitungan kompleks (pemformatan, pemfilteran, pengurutan) — gunakan @State untuk caching hasilnya atau keluarkan perhitungan ke metode terpisah yang dipanggil dari onChange. Perhitungan berulang di body setiap kali pembaruan status — penyebab umum perlambatan animasi.
Aturan kelima: untuk daftar (List, ForEach) sediakan pengidentifikasi stabil melalui parameter id. Tanpa identitas stabil, ForEach membuat ulang semua elemen pada setiap perubahan, memanggil body untuk masing-masing elemen, bahkan jika hanya satu elemen yang berubah.
Pertanyaan yang sering diajukan
body — properti komputasi protokol View yang mengembalikan konten untuk ditampilkan. Ini adalah satu-satunya persyaratan wajib protokol. Tipe kembalian — some View, yang memungkinkan SwiftUI mengoptimalkan hierarki pada tahap kompilasi.
Ya, SwiftUI memanggil body setiap kali terjadi perubahan status (@State, @Binding, @ObservedObject) atau data masukan. Ini adalah perilaku normal kerangka kerja deklaratif. SwiftUI mengoptimalkan frekuensi pemanggilan melalui mekanisme identitas dan perbandingan Equatable.
some View — tipe buram yang memungkinkan Anda menyembunyikan implementasi konkret. Kompiler menetapkan tipe pada tahap kompilasi, memastikan kinerja pemanggilan langsung. Ini memberikan fleksibilitas: Anda dapat mengubah tipe kembalian tanpa mengubah tanda tangan.
Tidak, body tidak bisa bersifat opsional — tipe kembalian some View tidak mengizinkan nil. Jika perlu menyembunyikan elemen secara kondisional, gunakan logika kondisional di dalam @ViewBuilder atau kembalikan EmptyView, yang tidak memakan tempat dalam hierarki.
Setiap pengubah membuat lapisan baru ModifiedContent, meningkatkan kedalaman hierarki. Untuk sebagian besar layar (hingga 50 pengubah) dampaknya tidak terasa. Jumlah pengubah yang berlebihan (ratusan) dapat memperlambat diffing. Kelompokkan pengubah terkait dalam ekstensi kustom.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga