body özelliği, SwiftUI'de View protokolünün merkezi öğesidir ve ekranda hangi içeriğin görüntüleneceğini belirler. Apple Developer Documentation, 2024'e göre, body View protokolünün tek zorunlu gereksinimidir ve aynı protokole uygun bir tür döndürür. SwiftUI, yeni bir öğe ağacı oluşturmak ve karşılaştırmak için her durum değişikliğinde body'yi çağırır.
Önemli Noktalar
body, View protokolünün tek zorunlu gereksinimi olan hesaplanan bir özelliktir. View'a uyan her yapı body'yi uygulamalıdır. Bu özellik, SwiftUI'nin ekranda görüntülediği içeriği döndürür — bu metin, bir resim, bir düğme, iç içe öğeler içeren bir kapsayıcı veya View protokolüne uyan başka bir tür olabilir.
body'nin imzası her zaman sabittir: var body: some View { get }. Dönüş türü some View (opak bir tür)'dür, somut bir tür değil. Bu, farklı Views'lerin body'de farklı somut türler döndürebileceği, ancak Swift derleyicisinin her uygulama için derleme zamanında somut türü sabitleyeceği anlamına gelir.
WWDC 2022'ye göre body, bildirimsel arayüz tanımlamasının giriş noktasıdır. UIView'i zorunlu olarak oluşturup yapılandırdığınız UIKit'in aksine, SwiftUI'de neyin görüntüleneceğini bildirimsel olarak tanımlarsınız ve SwiftUI bunu nasıl uygulayacağını kendisi hesaplar.
body, saf bir fonksiyon gibi davranmalıdır — aynı girdilerle (yapı özellikleri ve durum) aynı View ağacını döndürmelidir. body harici değişebilir duruma (global değişkenler, @AppStorage sarmalayıcısı olmayan UserDefaults) bağlıysa, davranış tahmin edilemez hale gelir ve SwiftUI ekranı yanlış şekilde yeniden çizebilir.
Hesaplanan özellik body bir değer depolamaz — her erişildiğinde hesaplanır. SwiftUI durumun değiştiğini belirlediğinde, View yapısını yeniden oluşturur ve görüntüleme için güncel öğe ağacını almak üzere body'nin yeni değerini okur.
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Sayaç: \(count)")
.font(.largeTitle)
Button("Artır") {
count += 1
}
.padding()
.background(.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
}
}
Bu örnekte body, bir Text ve değiştiricilerle birlikte bir düğme içeren bir VStack döndürür. Düğmeye basıldığında, @State özelliği count artar, SwiftUI CounterView yapısını yeniden oluşturur ve yeni Text değeriyle güncellenmiş ağacı almak için body'yi tekrar çağırır.
Değiştiriciler (.font, .padding, .background, .foregroundColor, .cornerRadius) orijinal View'i değiştirmez, onu ModifiedContent — değişikliği ekleyen yeni bir tür ile sarar. Her değiştirici başka bir iç içe geçme seviyesi oluşturur ve bu, performans için dikkate alınması önemlidir.
body'nin dönüş türündeki some View sadece bir kural değil, derleyici gereksinimidir. Swift, body'deki tüm dönüş yollarının aynı somut türde olmasını gerektirir. @ViewBuilder olmadan bir dalda Text ve diğerinde Button döndüremezsiniz — derleyici hata verecektir.
struct ConditionalView: View {
var isReady: Bool
@ViewBuilder
var body: some View {
if isReady {
Text("Hazır")
.foregroundColor(.green)
} else {
ProgressView()
}
}
}
Body üzerindeki @ViewBuilder, derleme hatası olmadan koşullu mantık (if/else, switch) kullanılmasını sağlar. ViewBuilder otomatik olarak farklı dalları ConditionalContent — somut tür farklılıklarını gizleyen özel bir tür ile sarar. Dinamik arayüzler oluşturmak için bu önemli bir yetenektir.
@ViewBuilder olmadan derleyici tüm dönüş yolları için tek bir tür çıkarmaya çalışır. Türler farklıysa — hata oluşur. Bu nedenle SwiftUI, View bildirimlerinde body'ye örtük olarak @ViewBuilder uygular, ancak kullanıcı kodunda birden çok Views döndüren özel yöntemler ve özellikler için açıkça ek açıklama eklemeniz gerekir.
Somut bir tür yerine some View kullanmak performansı düşürmez — derleyici derleme zamanında tam türü bilir ve dinamik dağıtım olmadan doğrudan kod oluşturur. AnyView ise varoluşsal bir kapsayıcıya sarma yüküyle tür silme (type erasure) kullanır.
body, SwiftUI tarafından üç ana senaryoda çağrılır: View ilk kez görüntülendiğinde, @State/@Binding/@ObservedObject/@StateObject değiştiğinde ve üst View başlatıcı aracılığıyla yeni değerler aktardığında. SwiftUI, ortam değerleri (@Environment) değiştiğinde de body'yi çağırabilir.
body çağrılarının sıklığı sizi endişelendirmemelidir — SwiftUI, kimlik mekanizması aracılığıyla yeniden çizmeyi optimize eder. Hiyerarşideki her View'in benzersiz bir tanımlayıcısı vardır. Kimlik ve girdi verileri değişmemişse — üst View yeniden çizilse bile body çağrılmaz. Bu, Equatable karşılaştırması ve yapısal kararlılık yoluyla elde edilir.
struct ParentView: View {
var body: some View {
ChildView(name: "Alice") // Kararlı kimlik
}
}
struct ChildView: View {
let name: String
var body: some View {
Text("Merhaba, \(name)!")
}
}
Bu örnekte, ParentView yeniden çizilirse ancak aynı name değerini aktarırsa — ChildView.body çağrılmaz. SwiftUI yapının girdi verilerini karşılaştırır ve değişmemişse alt bileşenin yeniden çizilmesini atlar. Bu, görünüm farklılaştırma mekanizmasıdır.
Body'nin beklenmedik şekilde çağrılmasına yol açan birkaç tuzak vardır: ObservableObject olmadan sınıf kullanımı, body içinde oluşturulan closure'ların iletilmesi (her closure oluşturma yeni bir kimlik verir) ve EquatableView'in yanlış kullanımı. body çok sık çağrılıyorsa — tüm alt bileşenlerin kimlik kararlılığını kontrol edin.
Birinci kural: body minimal olmalıdır. Karmaşık mantığı, View döndüren ayrı hesaplanan özelliklere veya yöntemlere taşıyın. Bu, okunabilirliği artırır ve SwiftUI'nin hiyerarşinin hangi bölümlerinin değiştiğini daha doğru belirlemesini sağlar. Büyük body'leri net sorumluluk sınırları olan alt bileşenlere bölün.
İkinci kural: iş yapmak için body'yi kullanmayın. Veri yükleme, ağ işlemleri, veritabanı yazma — tüm bunlar body dışında, görevler (tasks), onChange değiştiricileri veya ObservableObject aracılığıyla gerçekleşmelidir. body yalnızca arayüz bildirimi içindir.
Üçüncü kural: standart yapısal karşılaştırma yetersizse, Views için EquatableView özelliğini veya özel bir Equatable protokolü kullanın. Bu, SwiftUI'ye bir alt View'in ne zaman yeniden çizilmesi gerektiğini açıkça belirtmenizi ve gereksiz body çağrılarını önlemenizi sağlar.
Dördüncü kural: body karmaşık hesaplamalar (biçimlendirme, filtreleme, sıralama) içeriyorsa — sonucu önbelleğe almak için @State kullanın veya hesaplamaları onChange'den çağrılan ayrı bir yönteme taşıyın. Her durum güncellemesinde body'de tekrarlanan hesaplamalar, animasyon yavaşlamasının yaygın bir nedenidir.
Beşinci kural: listeler (List, ForEach) için id parametresi aracılığıyla kararlı tanımlayıcılar sağlayın. Kararlı kimlik olmadan ForEach, herhangi bir değişiklikte tüm öğeleri yeniden oluşturur ve her biri için body'yi çağırır (yalnızca bir öğe değişmiş olsa bile).
Sıkça Sorulan Sorular
body, görüntülenecek içeriği döndüren View protokolünün hesaplanan özelliğidir. Protokolün tek zorunlu gereksinimidir. Dönüş türü some View'dir ve SwiftUI'nin derleme zamanında hiyerarşiyi optimize etmesini sağlar.
Evet, SwiftUI her durum değişikliğinde (@State, @Binding, @ObservedObject) veya girdi verisi değişikliğinde body'yi çağırır. Bu, bildirimsel bir çerçeve için normal davranıştır. SwiftUI, kimlik mekanizması ve Equatable karşılaştırması yoluyla çağrı sıklığını optimize eder.
some View, somut uygulamayı gizleyen opak bir türdür. Derleyici türü derleme zamanında sabitleyerek doğrudan çağrı performansı sağlar. Bu esneklik sunar: imzayı değiştirmeden dönüş türünü değiştirebilirsiniz.
Hayır, body isteğe bağlı olamaz — dönüş türü some View nil'e izin vermez. Bir öğeyi koşullu olarak gizlemeniz gerekiyorsa, @ViewBuilder içinde koşullu mantık kullanın veya hiyerarşide yer kaplamayan EmptyView döndürün.
Her değiştirici yeni bir ModifiedContent katmanı oluşturarak hiyerarşi derinliğini artırır. Çoğu ekran için (50 değiştiriciye kadar) etki ihmal edilebilir düzeydedir. Aşırı değiştirici sayısı (yüzlerce) farklılaştırmayı yavaşlatabilir. İlgili değiştiricileri özel uzantılarda gruplandırın.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun