SwiftUI Property Wrappers Nedir? Nasıl Kullanılır?

Bengi Anıl
Ford Otosan
Published in
4 min readOct 27, 2023
SwiftUI Property Wrappers Türleri

Bu yazıda, SwiftUI kullanarak yazdığım uygulamalarımda en çok ihtiyaç duyduğum 5 property wrapper’a odaklanacağız; bunların tanımlarını, nasıl kullanacağımızı ve ne zaman tercih etmemiz gerektiğine değineceğiz.

Property Wrappers Nedir?

SwiftUI, uygulama geliştiricilerine kullanımı kolay ve güçlü bir araç seti sunar. Bu araç setinin temel taşlarından biri de “property wrapper”lardır. Aslında Property Wrappers, SwiftUI’da özellikleri tanımlamanın yenilikçi bir yoludur. Property Wrappers sayesinde temiz ve yeniden kullanılabilir kod yazmamız ve yönetmemiz kolaylaşır.

Peki nedir bu sık kullanacağımız property wrapper’lar dersek;

Sık kullanılan SwiftUI Property Wrappers

1. @State:

  • Tanım: @State property wrapper’ı, bir view’ın içindeki durumu temsil eder. State, bir view’ın içindeki değerlerin değişmesine ve bu değişikliklere tepki vermesine olanak tanır. Değerleri değiştiğinde UI güncellemelerini otomatik olarak tetikleyen değişken özellikleri oluşturmamızı sağlar.
  • Kullanım Alanları: Özellikle bir view içindeki değişen verileri yönetmek için kullanılır. View içindeki bir değişkenin değeri değiştiğinde, view otomatik olarak yeniden çizilir. Dinamik olarak değişmesi gereken UI öğeleri için kullanımı çok uygundur.

Haydi aşağıdaki sayaç örneğini inceleyelim:

struct CounterView: View {
@State private var count = 0

var body: some View {

VStack {
Text("Count: \(count)")
Button("Increment") {
count += 1
}
}
}
}

Burada count parametresini @State olarak tanımlıyoruz. Sebebi ise eğer bu şekilde tanımlamaz isek UI’da count değerini güncelleyemeyiz. Bu sebeple güncellenmesini takip edebilmek için @State dememiz gerekir. Increment butonuna tıklandıkça count değeri artar ve UI’da da güncellenmiş haliyle görünür.

2. @Binding:

  • Tanım: @Binding property wrapper’ı, bir değerin başka bir yerdeki değere bağlı olduğunu belirtir.
  • Kullanım Alanları: Bir view içindeki değeri, başka bir view’a iletmeye yarar. İki view arasında veri iletimini sağlamak için kullanabiliriz.

Parent-Child örneğiyle açıklayacak olursam:

struct ParentView: View {
@State private var name = ""

var body: some View {
VStack {
TextField("Enter your name", text: $name)
ChildView(data: $name)
}
}
}

struct ChildView: View {
@Binding var data: String

var body: some View {
Text(data)
}
}

ParentView’da değişen name parametresi (State kullanarak güncellendiğini de görebilirsiniz) ChildView’da @Binding olarak tanımladığımız için başka bir view’a aktarabilmiş ve o değişimi takip edebilmiş olduk. Bu SwiftUI’da kullanılan en basit veri aktarım yöntemidir.

Burada girilen isim değeri ChildView’a aktarılır, girilen ismi aynı şekilde orada da görebilmiş oluruz, ismi silersek veya değiştirirsek değişiklik anlık olarak ChildView’daki text’e de yansır. Biz ismi sadece ilk sayfadan değiştirmiş olsak da bu değişiklik ikinci sayfada da görülür.

Özetle State’in bir view’a özgü olduğunu, Binding’in ise view’lar arasında bir köprü görevi gördüğünü söyleyebiliriz.

3. @ObservableObject:

  • Tanım: @ObservableObject protokolü, bir nesnenin dışarıdan gözlemlenebilir (observable) olduğunu belirtir. Bu protokolü kullanarak, bir nesnenin içindeki değişkenlere yapılan değişiklikleri takip edebilir ve @ObservedObject ile birlikte kullanabilirsiniz.
  • Kullanım Alanları: Daha karmaşık modelleri ve bu modellerin içindeki değişkenleri dışarıdan gözlemlenebilir hale getirmek için kullanılır.
class UserScoreData: ObservableObject {
@Published var score = 0
}

4. @ObservedObject:

  • Tanım: @ObservedObject property wrapper'ı, dışa bağımlılıkları takip etmek ve bu bağımlılıkların değişikliklerine tepki vermek için kullanılır. İşlev olarak State’e çok benzer ancak ondan daha kapsamlıdır. State sadece içinde bulunduğu view’a etki ederken, @ObservedObject tanımlı olduğu her view’da kullanılabilir. Aynı State’te olduğu gibi nesnedeki değişiklikleri gözlemlemesine ve kullanıcı arayüzünü buna göre güncellemesine izin verir.
  • State’ten bir farkı daha bulunmaktadır. @ObservedObject kullanırken dinlenmesi istediği sınıfa @ObservableObject protokolü uygulanmak zorundadır. Kısaca bir değişkeni depolamak için kullanılır. Sayfalar arası değişimleri otomatik olarak taşır.
  • Kullanım Alanları: View içindeki dışa bağımlılıkların (genellikle bir model sınıfı) değişikliklerini takip etmek için kullanılır.
struct ScoreView: View {
@ObservedObject var progress: UserScoreData

var body: some View {
Button("Increase Score") {
progress.score += 1
}
}
}

5. @StateObject:

  • Tanım: Genellikle bir View’ın yaşam döngüsü boyunca sürekli olarak kullanılacak olan nesnelerini tanımlamak için kullanılır.@ObservableObject protokolü ile kullanılması uygundur.
  • Kullanım Alanları: @ObservedObject ‘ten farklı olarak bir gözlemlenebilir nesnenin(observable object) ilk örneğini (instance) oluşturmak için kullanılır. Daha sonra bu instance’ı kullanmak istediğimizde ise devreye @ObservedObject girer.
struct ContentView: View {
@StateObject var progress = UserScoreData()

var body: some View {
VStack {
Text("Your score is \(progress.score)")
ScoreView(progress: progress)
}
}
}

@ObservableObject,@ObservedObject ve @StateObject ‘in kullanımının birleştirilmiş hali aşağıdaki gibidir;

class UserScoreData: ObservableObject {
@Published var score = 0
}

struct ScoreView: View {
@ObservedObject var progress: UserScoreData

var body: some View {
Button("Increase Score") {
progress.score += 1
}
}
}

struct ContentView: View {
@StateObject var progress = UserScoreData()

var body: some View {
VStack {
Text("Your score is \(progress.score)")
ScoreView(progress: progress)
}
}
}

Örnekte de görüldüğü üzere@ObservableObject,@ObservedObject ve @StateObject ‘in birlikte kullanılması en doğrusudur.

Burada “score” değeri UserScoreData içerisinde tanımlanmıştır. UserScoreData’yı gözlemleyerek içindeki “score” değerine ulaşıyoruz ve published yapıldığı için bu değeri izleyebiliriz. @Publishedproperty wrapper’ı, “score” değişikliklerinin view’a yeniden yüklemek için tetiklenmesi gerektiğini söyler. Böylece kullanıcı olarak değişiklikleri eş zamanlı takip edebilmiş oluruz.

Score App’i Görünümü

Son olarak@StateObjectile @ObservedObjectarasındaki en büyük farklılık; UserScoreData’nın instance’ı oluşturulurken @StateObject kullanır, oluşturulduktan sonra ise @ObservedObject kullanılmasıdır.

Benim sıkça kullandığım ve işime yarayan Property Wrapper’lar bunlardı, faydalı olması dileğiyle :)

Ford Otosan — Connected Products & Engineering Tribe
Mobile Software Development Team Member
Bengi Anıl

--

--