Property Wrapper, kod tekrarı olmadan özelliklere erişim ve değişikliğe bir mantık katmanı ekleyen bir Swift mekanizmasıdır. SwiftUI'da Property Wrappers, görünüm durumu yönetiminin temeli haline geldi: @State, @Binding, @ObservedObject, @StateObject ve @Environment. Swift belgelerine (2025) göre, özellik sarmalayıcıları projelerdeki kalıp kodu ortalama %40 oranında azaltır. Property Wrapper'ı anlamak, her iOS geliştiricisinin framework ile etkili bir şekilde çalışması için gereklidir.
Önemli Noktalar
Property Wrapper — sürüm 5.1 ile tanıtılan, özellik erişim mantığını ayrı bir türde kapsüllemeye izin veren bir Swift dil yapısıdır. Her sınıfta tekrar tekrar getter ve setter yazmak yerine, geliştirici sarmalayıcıyı bir kez bildirir ve türün önünde @ ek açıklamasıyla uygular. Swift, özelliği otomatik olarak belirtilen türe sarar ve okuma ve yazma sırasında wrappedValue ve projectedValue yöntemlerini çağırır. Apple'a (WWDC 2019) göre, Property Wrappers SwiftUI için önemli bir soyutlama haline geldi.
Bir özellik sarmalayıcısı, @propertyWrapper özelliğine sahip bir yapı veya sınıftır. İçeride, böyle bir tür, gerçek değeri döndüren ve ayarlayan wrappedValue özelliğini uygulamalıdır. Swift derleyicisi, orijinal özelliğe erişimleri wrappedValue çağrılarıyla değiştirir ve uygulamayı çağıran koddan tamamen gizler. Ek olarak, $ sembolü aracılığıyla erişilebilen bir yansıtma olan projectedValue tanımlanabilir.
Property Wrappers'ın avantajı, mantığın yeniden kullanılabilirliğinde yatar. Örneğin, e-posta doğrulama, değer önbelleğe alma veya depolama senkronizasyonu için bir sarmalayıcı oluşturabilir — ve bunu projedeki herhangi bir özelliğe uygulayabilirsiniz. SwiftUI'da bu kavram her yerde kullanılır: her durum yönetimi mekanizması ayrı bir Property Wrapper olarak uygulanmıştır.
@WrapperType var value: T ek açıklamasıyla bir özellik bildirirken, Swift derleyicisi kodu dönüştürür. WrapperType'ın bir örneğini oluşturur ve wrappedValue aracılığıyla özelliğe erişim oluşturur. Kaynak kod let x = value, let x = _value.wrappedValue'ye dönüşür ve value = newValue, _value.wrappedValue = newValue'ye dönüşür. Bu dönüşüm derleme zamanında gerçekleşir ve çalışma zamanı ek yükü yoktur.
@propertyWrapper
struct Capitalized {
private var text: String
var wrappedValue: String {
get { text }
set { text = newValue.capitalized }
}
init(initialValue: String) {
text = initialValue.capitalized
}
}
Listeleme, bir dizeyi otomatik olarak büyük harf biçimine dönüştüren Capitalized sarmalayıcısını gösterir. Bir değer atarken, setter kaydetmeden önce capitalized'i çağırır. Artık @Capitalized ek açıklamasına sahip herhangi bir özellik yalnızca doğru biçimlendirilmiş metni depolar. Bu yaklaşım, doğrulama ve biçimlendirme kodunun tekrarını tamamen ortadan kaldırır.
Yansıtma (projectedValue) — $ öneki aracılığıyla erişilebilen ek bir iletişim kanalıdır. SwiftUI'da bu özellik her yerde kullanılır: $state, Binding
SwiftUI, durum yönetimi için beş yerleşik Property Wrappers içerir: @State, @Binding, @ObservedObject, @StateObject ve @Environment. Her biri belirli bir görevi çözer ve farklı senaryolarda kullanılır. @State basit yerel veriler için, @Binding — alt görünümlere veri referansı iletmek için, @ObservedObject ve @StateObject — karmaşık nesneler için, @Environment — hiyerarşiden sistem değerleri için tasarlanmıştır.
| Sarmalayıcı | Amaç | Sahiplik |
|---|---|---|
| @State | Tek bir görünümün yerel durumu | Mevcut görünüm |
| @Binding | Ebeveyn ile çift yönlü bağlantı | Üst görünüm |
| @ObservedObject | Harici nesne gözlemi | Harici sahip |
| @StateObject | ObservableObject oluşturma | Mevcut görünüm |
| @Environment | Hiyerarşiden sistem değerleri | SwiftUI ortamı |
Belirli bir Property Wrapper seçimi, veri kaynağına ve yaşam döngüsüne bağlıdır. Veriler tek bir görünüme aitse ve alt bileşenler tarafından ihtiyaç duyulmuyorsa — @State kullanın. Bir alt görünümün ebeveynin verilerini değiştirmesi gerekiyorsa — @Binding kullanın. Birden çok görünümde kullanılan nesneler için @ObservedObject ve @StateObject uygundur.
@State, tek bir görünüm içinde yerel durumu depolamak için bir Property Wrapper'dır. SwiftUI, @State özellikleri için belleği otomatik olarak yönetir ve her değişiklikte görünümü yeniden çizer. @State, yalnızca mevcut görünüme ait olan basit türler (String, Int, Bool, enum) ve yapılar için uygundur. Değer değiştiğinde, SwiftUI body özelliğini yeniden çalıştırır.
struct CounterView: View {
@State private var count: Int = 0
var body: some View {
VStack {
Text("Sayım: \(count)")
Button("Artır") {
count += 1
}
}
}
}
Örnekte, @State özelliği count sayacın mevcut değerini depolar. SwiftUI bu özellik için yığında bir depolama alanı oluşturur ve bunu CounterView'ın yaşam döngüsüne bağlar. Düğmeye basıldığında, count 1 artar, SwiftUI değişikliği algılar ve body'yi yeniden çalıştırarak yeni değeri gösterir. Önemli: @State karmaşık referans türleri için kullanılmamalıdır — bunun için @StateObject ve @ObservedObject vardır.
@Binding, başka bir görünüme ait bir veri kaynağına referans oluşturur. Binding kendi başına bir değer depolamaz — verileri @State, @StateObject veya ebeveynden iletilen başka bir Binding aracılığıyla okur ve yazar. Bu, alt bileşenlerin verilere doğrudan sahip olmadan ve geri aramalar olmadan ata durumunu değiştirmesine olanak tanır.
struct ToggleSwitch: View {
@Binding var isOn: Bool
var body: some View {
Toggle("Switch", isOn: $isOn)
}
}
Listelemede, ToggleSwitch üst görünümden @BindingBool alır. Ebeveyn, @State var isToggleOn = false oluşturur ve $isToggleOn'u ToggleSwitch'in başlatıcısına iletir. Kullanıcı alt görünüm içindeki anahtarı değiştirdiğinde, değişiklik anında ebeveynin @State'ine yansır. Binding mekanizması, hiyerarşide yukarı doğru değişiklikleri iletmek için delegelere veya closure'lara olan ihtiyacı tamamen ortadan kaldırır.
@ObservedObject, dışarıdan iletilen bir ObservableObject örneğini gözlemlemek için bir Property Wrapper'dır. Görünüm bu nesneye sahip değildir — üst bileşende oluşturulur veya Environment aracılığıyla enjekte edilir. ObservableObject içindeki herhangi bir @Published özelliği değiştiğinde, SwiftUI @ObservedObject aracılığıyla abone olan tüm görünümleri yeniden çizer.
@StateObject — doğrudan görünümde ObservableObject oluşturmak ve sahiplenmek için bir sarmalayıcıdır. @ObservedObject'in aksine, @StateObject, görünümün tüm yaşam döngüsü boyunca nesnenin tek bir örneğini garanti eder. SwiftUI görünüm yapısını yeniden oluştursa bile (ki bu sık sık olur), @StateObject mevcut nesneyi korur ve başlatıcıyı yeniden çağırmaz.
class UserSettings: ObservableObject {
@Published var username: String = "Guest"
}
struct ProfileView: View {
@StateObject var settings = UserSettings()
var body: some View {
ChildProfileView(settings: settings)
}
}
struct ChildProfileView: View {
@ObservedObject var settings: UserSettings
var body: some View {
Text("Merhaba, \(settings.username)")
}
}
Örnekte, ProfileView @StateObject aracılığıyla UserSettings oluşturur ve nesnenin sahibi olur. ChildProfileView aynı örneği @ObservedObject aracılığıyla alır — gözlemler ancak yaşam döngüsünü yönetmez. username değiştiğinde, her iki görünüm de güncellenir. ChildProfileView @ObservedObject yerine @StateObject kullanmış olsaydı, her işlemede başlangıç değeriyle yeni bir örnek oluşturulurdu.
Ana kural: @StateObject, nesneyi oluşturan görünümde (gerçeğin kaynağı) kullanılırken, @ObservedObject, ebeveynden zaten oluşturulmuş bir nesneyi alan görünümde kullanılır. Bu kuralın ihlali, durum kaybına veya beklenmeyen veri yeniden oluşturulmasına yol açar.
Swift, herhangi bir tekrarlayan özellik erişim mantığı için özel Property Wrappers oluşturulmasına izin verir. Sadece @propertyWrapper özelliğine sahip bir yapı veya sınıf bildirin ve wrappedValue'yi uygulayın. Aşağıda, değeri otomatik olarak UserDefaults ile senkronize eden UserDefaultsWrapper sarmalayıcısı gösterilmektedir.
@propertyWrapper
struct UserDefaultsWrapper<T> {
let key: String
let defaultValue: T
var wrappedValue: T {
get { UserDefaults.standard.object(forKey: key) as? T ?? defaultValue }
set { UserDefaults.standard.set(newValue, forKey: key) }
}
}
struct AppConfig {
@UserDefaultsWrapper(key: "theme", defaultValue: "light")
var theme: String
}
UserDefaultsWrapper sarmalayıcısı, UserDefaults tarafından desteklenen herhangi bir veri türüyle çalışmak için genel bir T kullanır. Getter, değeri anahtarla okur, setter yazar. theme özelliğine @UserDefaultsWrapper(key:defaultValue:) uygulamak, onu otomatik olarak depolamaya bağlar — tüm UserDefaults mantığı sarmalayıcının içinde gizlidir. Bu, Property Wrappers ile kalıp kodun azaltılmasının tipik bir örneğidir.
Özel sarmalayıcılar oluştururken, performansı dikkate almak önemlidir. Getter ve setter özelliğe her erişimde çağrıldığından, wrappedValue'ya ağır G/Ç işlemleri yerleştirilmemelidir. Zaman uyumsuz veri depolama için, Property Wrappers'ı ObservableObject ve @Published ile birleştirmek daha iyidir.
Sıkça Sorulan Sorular
@State basit türler (String, Int, Bool) ve yapılar için tasarlanmışken, @StateObject ObservableObject uygulayan referans türleri içindir. @State değeri doğrudan SwiftUI'da depolar, @StateObject yığında bir sınıf örneğini yönetir.
Evet, @Binding @StateObject, @ObservedObject veya $ yansıtması kullanılarak başka bir Binding'den oluşturulabilir. Binding ayrıca ObservableObject'ten $object.$publishedProperty aracılığıyla veya InlineBinding'den Binding.constant(value) aracılığıyla başlatılabilir.
Global veriler için @EnvironmentObject kullanın veya ObservableObject'i EnvironmentValues aracılığıyla enjekte edin. @StateObject, kök görünüm için uygundur ve ardından @ObservedObject aracılığıyla alt bileşenlere iletilir.
@ObservedObject nesneye sahip değildir — üst görünüm yeniden oluşturulur ve yeni bir örnek iletirse, @ObservedObject ona geçer. Durum kaybını önlemek için, sahip olan görünüm @StateObject kullanmalıdır.
Evet, ancak sınıf içinde @Published ve async işlevleriyle ObservableObject kombinasyonunu kullanmak daha kolaydır. Property Wrapper doğası gereği senkronizedir — wrappedValue her erişimde hesaplanır, bu da uzun süren işlemler için uygun değildir.
Ö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