@ViewBuilder, SwiftUI'de View hiyerarşilerinin bildirimsel oluşturumu için tasarlanmış bir result builder ek açıklamasıdır. Apple Developer Documentation, 2024'e göre, @ViewBuilder birden çok ifade ve koşullu mantık içeren bir kod bloğunu Swift derleyicisinin anlayabileceği tek bir View türüne dönüştürür. Bu ek açıklama olmadan, if/else ve body içinde birden çok öğeyle tanıdık bildirimsel SwiftUI sözdizimini kullanmak imkansız olurdu.
Önemli Noktalar
@ViewBuilder, result builder desenini (SE-0289) uygulayan ve SwiftUI'nin bildirimsel sözdizimi kullanarak birden çok View'i tek bir kompozisyonda birleştirmesine olanak tanıyan bir ek açıklamadır. Birden çok ifadeyi, koşullu yapıları ve isteğe bağlı değerleri otomatik olarak ilgili türlerine sarar: TupleView, ConditionalContent, OptionalContent.
Result builder'lar ortaya çıkmadan önce, geliştiricilerin öğeleri manuel olarak VStack veya HStack içinde sarması ve koşullu mantık için üçlü operatörler veya fabrika yöntemleri kullanması gerekiyordu. @ViewBuilder, SwiftUI sözdizimini kısa ve okunabilir hale getirerek if/else ve döngülerle normal Swift gibi görünen kod yazmayı mümkün kıldı.
Swift Evolution SE-0289'a göre, result builder'lar SwiftUI'ye bağlı olmayan genel bir mekanizmadır. @ViewBuilder, bu mekanizmanın bir uygulamasıdır; ayrıca @StringBuilder (dizi oluşturma) ve diğer DSL'ler için kitaplık uygulamaları da vardır. SwiftUI'de @ViewBuilder yalnızca body için değil, aynı zamanda kapsayıcıların (VStack, HStack, ZStack, List) closure parametreleri için de kullanılır.
Emir kipi UIKit'te, açıkça bir UIView oluşturur, özelliklerini yapılandırır ve addSubview aracılığıyla hiyerarşiye eklersiniz. @ViewBuilder ile SwiftUI'de, hangi View'lerin görüntüleneceğini bildirimsel olarak tanımlarsınız ve SwiftUI, durum değişikliklerine göre öğelerin oluşturulmasını, güncellenmesini ve kaldırılmasını yönetir.
Result builder, static yöntemler buildBlock, buildOptional, buildEither ve diğerleri aracılığıyla bir ifade dizisini tek bir bileşik değere dönüştüren bir Swift mekanizmasıdır. Derleyici @ViewBuilder ek açıklamasını gördüğünde, derleme sırasında bu yöntemleri otomatik olarak kod bloğuna uygular.
@resultBuilder
struct ViewBuilder {
static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) -> TupleView<(C0, C1)>
static func buildIf<C>(_ c: C?) -> C?
static func buildEither<T, F>(first: T) -> ConditionalContent<T, F>
static func buildEither<T, F>(second: F) -> ConditionalContent<T, F>
}
buildBlock 1 ila 10 ifadeyi kabul eder ve bir TupleView döndürür. Her arite (ifade sayısı) kendi buildBlock aşırı yüklemesine sahiptir: buildBlock
buildEither (first/second) if/else yapılarını işler. Her dal ilgili yönteme iletilir ve sonuç ConditionalContent içinde sarılır — bu, belirli dal türlerini gizleyen ve SwiftUI için birleşik bir arayüz sağlayan bir türdür.
SwiftUI'de, body özelliği zaten örtük olarak @ViewBuilder ile ek açıklamalıdır — bu ek açıklamayı kodda görmezsiniz, ancak derleyici onu otomatik olarak uygular. Ancak, birden çok View döndüren özel özellikler veya closure parametreleri için ek açıklamanın açıkça belirtilmesi gerekir.
Sınırlama 1 — bir blokta 10 öğe. Bu, @ViewBuilder'ın en bilinen sınırlamasıdır. Aynı seviyede 10'dan fazla öğe görüntülemeniz gerekiyorsa, derleyici bir hata verecektir. Çözümler arasında Group, ForEach, List veya alt bileşenlere ayırma bulunur. Group görsel iç içe eklemez, ancak her Group bir öğe olarak sayılır.
struct ManyElementsView: View {
var body: some View {
Group {
Text("1"); Text("2"); Text("3")
Text("4"); Text("5"); Text("6")
Text("7"); Text("8"); Text("9")
}
Group {
Text("10"); Text("11"); Text("12")
}
}
}
Sınırlama 2 — bazı yapılar için destek eksikliği. @ViewBuilder do/catch, guard, for-in (ForEach olmadan) ve diğer kontrol akışı yapılarını desteklemez. Döngüler için, tanımlanabilir verilerle ForEach kullanın. Hata işleme için, Result veya isteğe bağlı değerler kabul eden ayrı View'ler kullanın.
Sınırlama 3 — hata ayıklama karmaşıklığı. @ViewBuilder'da hatalar oluştuğunda, derleyici, temel nedeni bulmanın zor olduğu ayrıntılı mesajlar üretir. Tipik sorunlar: if/else dallarında tür uyuşmazlığı, 10 öğe sınırının aşılması veya gerekli buildBlock aşırı yüklemelerinin olmaması.
Desen 1: if/else ile koşullu görüntüleme. @ViewBuilder'ın en yaygın kullanım durumu. Üçlü operatörler veya fabrika yöntemleri kullanmadan duruma bağlı olarak farklı View'ler göstermeye olanak tanır.
struct StatusView: View {
var status: LoadStatus
@ViewBuilder
var body: some View {
switch status {
case .loading:
ProgressView("Loading...")
case .loaded(let data):
DataView(data: data)
case .error(let message):
ErrorView(message: message)
}
}
}
Desen 2: işlev ve başlatıcı parametrelerinde @ViewBuilder. Bir closure aracılığıyla alt View'leri kabul eden yeniden kullanılabilir kapsayıcılar oluşturmak için kullanılır. Bu, kitaplıklar ve UI bileşenleri için standart desendir.
struct SectionCard<Content: View>: View {
let title: String
@ViewBuilder let content: Content
var body: some View {
VStack(alignment: .leading) {
Text(title).font(.headline)
content
}
.padding()
.background(Color.gray.opacity(0.1))
.cornerRadius(12)
}
}
Desen 3: ForEach ile kompozisyon. @ViewBuilder, ForEach ile doğru şekilde çalışarak bir veri dizisinden öğelerin dinamik olarak oluşturulmasına olanak tanır. ForEach'in her öğesi, @ViewBuilder bağlamında bir ifade olarak sayılır.
Özel ViewBuilder, @ViewBuilder ile ek açıklamalı ve some View döndüren kullanıcı tanımlı bir işlev veya özelliktir. Bu tür işlevler, karmaşık görüntüleme mantığını kapsüllemeye ve uygulamanın farklı bölümlerinde yeniden kullanmaya olanak tanır.
struct FormRow<Content: View>: View {
let label: String
@ViewBuilder let content: Content
var body: some View {
HStack {
Text(label)
.frame(width: 120, alignment: .trailing)
content
}
}
}
// Kullanım:
FormRow(label: "Name") {
TextField("Enter name", text: $name)
}
FormRow(label: "Gender") {
Picker("Select", selection: $gender) {
Text("Erkek").tag(Gender.male)
Text("Kadın").tag(Gender.female)
}
}
Önemli kural: @ViewBuilder ile özel bir işlev, somut bir tür veya View protokolü değil, some View döndürmelidir. Yalnızca opak tür, kompozisyon esnekliğini korurken somut uygulamayı gizlemeye olanak tanır.
Performans: özel @ViewBuilder işlevleri, doğrudan body koduna kıyasla ek yük eklemez. Derleyici çağrıları satır içi yapar ve sonuç kodunu optimize eder. Body'yi @ViewBuilder işlevlerine bölmek, performanstan ödün vermeden okunabilirliği artırır.
Sıkça Sorulan Sorular
@ViewBuilder, birden çok ifade ve koşul içeren bir kod bloğunu tek bir View türüne dönüştüren bir result builder ek açıklamasıdır. SwiftUI'nin bildirimsel UI'sı içinde tanıdık Swift sözdizimini (if/else, switch, isteğe bağlı ifadeler) kullanmaya olanak tanır.
Sınırlama, buildBlock uygulamasından kaynaklanır — 1'den 10'a kadar her arite için yöntemin ayrı bir aşırı yüklemesi vardır. Swift değişken jenerikleri desteklemez, bu nedenle aşırı yükleme sayısı sabittir. Bunu aşmak için Group, ForEach veya alt bileşenler kullanın.
Hayır, View protokolü body özelliğine @ViewBuilder'ı örtük olarak uygular. Ancak, birden çok View döndüren özel özellikler, yöntemler ve closure parametreleri için ek açıklamanın açıkça belirtilmesi gerekir. Aksi takdirde derleyici birden çok ifadeyi işleyemez.
İsteğe bağlı ifadeler için, isteğe bağlı bir View kabul eden ve bir değer varsa onu döndüren buildIf yöntemi kullanılır. Değer nil ise, buildIf nil döndürür ve öğe görüntülenmez. Bu, body içinde if let kullanmaya olanak tanır.
Evet, Swift 5.9'dan itibaren @ViewBuilder, buildExpression yöntemi aracılığıyla switch'i destekler. Derleyici her case dalını ilgili buildEither çağrısına dönüştürür. Switch desteği, iç içe if/else yapılarına kıyasla kodu daha okunabilir hale getirir.
Ö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