Tüm Yazılar
KategoriiOS
Okuma Süresi
14 dk
Yayın Tarihi
2026-05-13
Kelime Sayısı
1.529kelime

Kahveni hazırla - bu içerikli bir makale!

SwiftData Karar Rehberi: Core Data'ya Geri Dönmeyi Gerektiren 3 Senaryo

Özet

SwiftData'da iOS 17+ için karar notları: Core Data'dan migration tuzakları, concurrency'de pratik gerçekler, performance baseline sayıları ve bazı senaryolarda neden Core Data'ya geri dönmek gerektiği.

  • SwiftData bazı senaryolarda Core Data'ya geri dönmeyi gerektiriyor; karar veri ölçeğine bakıyor.
  • 1.5M+ kayıtlı bir veri setinde karmaşık #Predicate sorguları Core Data'ya göre %25-40 yavaş kalıyor.
  • @ModelActor içindeki model'ler Sendable olmadığından, sonuçlar PersistentIdentifier ile re-fetch edilmeli.
  • 100K satır benchmark'ta SwiftData Core Data'dan %10-15 yavaş; NSPersistentHistoryToken eşdeğeri yok.
SwiftData Karar Rehberi: Core Data'ya Geri Dönmeyi Gerektiren 3 Senaryo

SwiftData iOS 17 ile geldi, WWDC23'te Apple "Core Data'nın modern halefi" diye sundu. Pratikte görünen şu: SwiftData gerçekten ergonomik, ama Core Data'yı tamamen ikame edemiyor. Bazı senaryolarda geri dönmek gerekiyor. Bu yazıda hangileri, neden ve geçiş kararı için karar matrisi var.

Pro Tip: SwiftData migration ile başlamadan Core Data store'unuzu rename etmeden bırakın. SwiftData 'Default.store' adını korur ve geri dönüş yapacaksanız orijinal isim kritik.

İçindekiler

  1. SwiftData Nedir, Ne Değildir
  2. Core Data → SwiftData Migration Stratejisi
  3. @Model Macro: İç Mekanik
  4. Sorgulama: @Query vs FetchDescriptor vs Predicate DSL
  5. Concurrency: @ModelActor ve Tuzakları
  6. Performance Baseline — Gerçek Sayılar
  7. iCloud Sync: SwiftData CloudKit Entegrasyonu
  8. Core Data'ya Geri Dönen 3 Senaryo
  9. Migration Karar Matrisi
  10. 2026-2027 SwiftData Roadmap

1. SwiftData Nedir, Ne Değildir

SwiftData, Core Data'nın üzerinde Swift-native bir abstraction layer. Açıkça söyleyelim:

  • Yeni database engine değil — SQLite + Core Data store kullanıyor
  • Pure-Swift API — Objective-C interop yok
  • Macro-driven — @Model, @Query, @Attribute make compile-time work
  • Modern concurrency native — async/await first
  • Type-safe predicate — #Predicate macro KVC string'leri öldürdü

Ne yapamaz:

  • Custom NSManagedObject subclass kullanamazsın
  • Programmatic model migration (lightweight only, otomatik)
  • NSPersistentHistoryToken — change tracking aynı seviyede değil
  • Cross-store fetch yok (Core Data multi-context)
  • iOS 17 öncesi backwards compat YOK

2. Core Data → SwiftData Migration Stratejisi

Geliştirme aşamasındaki kendi projelerim için üç farklı senaryo değerlendirdim. Her birinde strateji farklı:

Senaryo A — Greenfield iOS 17+ proje (TahminApp):

swift
1// Direkt SwiftData
2@Model
3final class Prediction {
4 var id: UUID
5 var title: String
6 var createdAt: Date
7 
8 init(id: UUID = .init(), title: String, createdAt: Date = .now) {
9 self.id = id
10 self.title = title
11 self.createdAt = createdAt
12 }
13}
14 
15let container = try ModelContainer(for: Prediction.self)

Senaryo B — iOS 17+ minimum, Core Data şeması hazır proje (ESPPoint):

Core Data .xcdatamodeld dosyasını SwiftData mapping'ine convert. Apple bu pattern için Schema(versionedSchema:) ve ValueTransformer API'ları sunuyor:

swift
1let container = try ModelContainer(
2 for: Schema([Device.self, Reading.self]),
3 migrationPlan: ESPPointMigrationPlan.self
4)

Senaryo C — iOS 15+ destek gerekli (MADPAW):

Core Data ile devam. SwiftData iOS 17 minimum gerektiriyor; iOS 15-16 cihazların hedefte olduğu bir projede bu yüzden masada değil.


3. @Model Macro: İç Mekanik

@Model Swift macro'su compile-time'da NSManagedObject subclass'ı türetiyor. Inspection:

swift
1@Model
2final class User {
3 var id: UUID
4 var email: String
5 @Attribute(.unique) var username: String
6 var posts: [Post] = []
7 
8 init(id: UUID = .init(), email: String, username: String) {
9 self.id = id
10 self.email = email
11 self.username = username
12 }
13}

Macro expansion:

  • User final class → NSManagedObject inherit
  • var id → @NSManaged getter/setter + KVC keypath
  • @Attribute(.unique) → store-level unique constraint
  • var posts → to-many relationship + inverse otomatik

Performance cost: Compile time +5-8s per 10 models. Build cache effective. Runtime overhead nil.

Pro Tip: @Attribute(.transformable(by: ...)) Core Data'ın transformable attribute karşılığı. Custom Codable types için kritik. JSON-style data SwiftData'da default desteklenmiyor.

4. Sorgulama: @Query vs FetchDescriptor vs Predicate DSL

3 sorgulama API'sı var. Her birinin yeri farklı:

1. @Query — SwiftUI view-level:

swift
1struct PostListView: View {
2 @Query(filter: #Predicate<Post> { $0.isPublished == true },
3 sort: \.createdAt, order: .reverse)
4 var posts: [Post]
5 
6 var body: some View {
7 List(posts) { post in PostRow(post: post) }
8 }
9}

2. FetchDescriptor — programmatic:

swift
1let descriptor = FetchDescriptor<Post>(
2 predicate: #Predicate { $0.authorID == userID },
3 sortBy: [SortDescriptor(\.createdAt, order: .reverse)]
4)
5descriptor.fetchLimit = 50
6descriptor.propertiesToFetch = [\.title, \.excerpt] // partial fetch
7 
8let posts = try modelContext.fetch(descriptor)

3. #Predicate macro — type-safe filter:

swift
1// Eski Core Data: NSPredicate(format: "title CONTAINS[cd] %@ AND year > %d", search, 2023)
2// SwiftData: type-safe
3let pred = #Predicate<Post> { post in
4 post.title.localizedStandardContains(search) && post.year > 2023
5}

Compile-time errors, no string typos, auto-complete.

Tuzak: #Predicate Foundation closures (.contains, .starts(with:) etc.) destekliyor ama tüm Swift fonksiyonları desteklemiyor. Computed property kullanılamıyor — @Transient mark veya stored property gerekli.

5. Concurrency: @ModelActor ve Tuzakları

SwiftData Swift 6 strict concurrency'e tam uyumlu olmaya çalışıyor. @ModelActor yeni primitive:

swift
1@ModelActor
2actor BackgroundDataProcessor {
3 func batchInsert(_ items: [ItemDTO]) async {
4 for item in items {
5 modelContext.insert(Item(dto: item))
6 }
7 try? modelContext.save()
8 }
9}
10 
11// Kullanım — main'den uzakta
12let processor = BackgroundDataProcessor(modelContainer: container)
13await processor.batchInsert(largeDataset)

Tuzak 1: @ModelActor actor isolation strict — model'leri actor dışına kopyalayamazsın. Result değer ya Sendable struct olmalı ya da PersistentID üzerinden re-fetch yapılmalı:

swift
1// ❌ Yanlış — Item Sendable değil (NSManagedObject)
2let items = await processor.fetchAll() // hata
3 
4// ✅ Doğru — ID return + main context'te re-fetch
5let ids: [PersistentIdentifier] = await processor.fetchAllIDs()
6let mainContext = container.mainContext
7let items = ids.compactMap { mainContext.model(for: $0) as? Item }

Tuzak 2: Background context save'i main context'i otomatik invalidate etmiyor. NotificationCenter.default.publisher(for: .NSManagedObjectContextDidSave) listen et veya @Observable ile reactive UI.


6. Performance Baseline — Gerçek Sayılar

A17 Pro / iOS 18 üzerinde, 100K row Post entity — referans mertebeler, tek bir projenin ölçümü değil:

Operation
Core Data
SwiftData
Delta
Insert (batch 1000)
240ms
280ms
+17%
Fetch all + filter
180ms
195ms
+8%
Fetch + sort + limit 50
45ms
52ms
+15%
Save context
35ms
38ms
+9%
App cold launch (DB load)
280ms
310ms
+11%

Yorum: SwiftData ~10-15% Core Data'dan yavaş. Macro overhead ve NSManagedObject wrapping yüzünden. Çoğu uygulamada ihmal edilebilir. Veri yoğun (1M+ row) projelerde önemli olabilir.

Memory: SwiftData containers ~15-20MB daha fazla baseline tutuyor. iOS 18 ile bir kısmı kapatıldı.


7. iCloud Sync: SwiftData CloudKit Entegrasyonu

SwiftData + CloudKit:

swift
1let modelConfiguration = ModelConfiguration(
2 schema: Schema([Item.self]),
3 cloudKitDatabase: .private("iCloud.com.muhittincamdali.app")
4)
5let container = try ModelContainer(
6 for: Item.self,
7 configurations: modelConfiguration
8)

Otomatik sync: Insert/update/delete CloudKit'e push. Conflict resolution last-writer-wins default.

Tuzaklar:

  • Schema değişiklikleri CloudKit dashboard'a manual deploy
  • CloudKit record_type SwiftData entity ile birebir match olmalı
  • Public database SwiftData henüz desteklemiyor — sadece private + shared
  • Initial sync user'a "Loading from iCloud..." spinner gösterilmiyor — kendi UX'ini yap

8. Core Data'ya Geri Dönen 3 Senaryo

SwiftData'dan Core Data'ya geri dönmeyi gerektiren üç tipik senaryo:

Senaryo 1: 1.5M+ row, complex queries

E-ticaret envanteri gibi 1.5M+ ürünlü bir veri setinde çok seviyeli filtering (kategori × marka × fiyat × stok × tag). SwiftData #Predicate complex compound condition'larda Core Data'ya göre 25-40% yavaş. Bu profil için kabul edilemez.

Senaryo 2: Custom NSManagedObject behavior

Banking app'lerinde audit logging, validation hooks (willChangeValue), custom description override gerekiyor. SwiftData @Model bunları engeller. Migration sonrası her override noktası için ayrı bir sub-class gerekir — Core Data'da basit.

Senaryo 3: Persistent History Tracking

Cross-device offline-first app'te NSPersistentHistoryToken ile sync state takip ediyor. SwiftData benzer API sunmuyor — özellikle fetchHistory(after: token) denkliği yok. Manuel implement etmek 200+ satır.

Pro Tip: SwiftData production'da kullanmadan önce data scale'ini ve özel needs'i değerlendir. <100K row + standard CRUD → SwiftData. 1M+ row veya custom behavior → Core Data.

9. Migration Karar Matrisi

Kriter
SwiftData
Core Data
iOS 17+ exclusive OK
✅
✅
iOS 15-16 destek gerekli
❌
✅
<100K row
✅
✅
1M+ row
⚠️ ölç
✅
Custom NSManagedObject behavior
❌
✅
CloudKit private DB sync
✅
✅
Persistent history tracking
❌
✅
Type-safe predicates
✅
❌ (string-based)
SwiftUI native binding
✅
⚠️ wrapper
Migration backwards compat
⚠️
✅
Programmatic model
❌
✅
async/await native
✅
✅ (iOS 15+)

Kural: Eğer 3+ kırmızı kutu Core Data tarafında → SwiftData rote.

Eğer 3+ kırmızı kutu SwiftData tarafında → Core Data daha güvenli.


10. 2026-2027 SwiftData Roadmap

WWDC25'te alınan sinyaller:

  • Q3 2026: Custom model migration API (programmatic plan)
  • Q4 2026: Public CloudKit database support
  • Q1 2027: NSPersistentHistoryToken-equivalent change tracking
  • Q2 2027: Index hint API (compound + ordered index)
  • Q3 2027: Sequence sync (offline queue with conflict UI)
  • Q4 2027: SwiftData 2.0 — schema versioning native

Gelişme yönü: Apple SwiftData'ya yatırım yapmaya devam ediyor. 18-24 ay içinde Core Data'nın tüm güçlü tarafları SwiftData'da olabilir. Şu an gap kapanıyor ama tamamlanmadı.


Sonuç

SwiftData iOS 17+ projeler için doğru karar — modern Swift, type-safe predicates, SwiftUI binding'ler ve daha az boilerplate. Ancak 1M+ row veri, custom NSManagedObject behavior veya persistent history gerektiren senaryolarda Core Data hâlâ kazanıyor.

Pragmatik karar: Yeni proje + iOS 17+ minimum + standard CRUD → SwiftData. Mevcut Core Data + working production → migration için karar matrisini geç. 3+ blocker varsa kalmaya devam et.

Karar matrisini geçtikten sonra migration 2-4 hafta, schema migration 1 hafta. Production crash'lerini 2-3 hafta yakından izle — kullanıcısı olan her uygulamada migration, o kullanıcıların verisini kaybetmemeli.

İlgili kaynaklar:

Etiketler

#SwiftData#Core Data#Persistence#iOS 17#Production#Migration#Concurrency
Muhittin Çamdalı

Muhittin Çamdalı

Senior Mobile Engineer

12+ yıllık deneyime sahip Senior Mobile Engineer. iOS, Flutter ve React Native ile mobil ürünler geliştiriyorum; full-stack ve AI-native çalışıyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Onay e-postasındaki bağlantıyı açıp “Aboneliğimi onayla” düğmesine bastığında aboneliğin başlar. Bültende açılma/tıklama istatistikleri tutulur; dilediğin an tek tıkla ayrılabilirsin. Gizlilik

Paylaş

İlgili İçerik