Tüm Yazılar
KategoriiOS
Okuma Süresi
24 dk
Yayın Tarihi
...
Kelime Sayısı
1.580kelime

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

iOS 17+ SwiftData framework'ü ile modern veri yönetimi. Model tanımlama, query'ler, relationships, migration ve CloudKit sync.

SwiftData Complete Guide: Core Data'nın Modern Halefi

Core Data ile çalışmak hiç kolay değildi. NSManagedObjectContext, NSFetchRequest, NSPredicate... Tüm bu karmaşık API'lar sadece "bir veriyi kaydetmek" için fazla. Apple bunu biliyordu ve WWDC23'te SwiftData'yı duyurarak oyunu değiştirdi. SwiftData, Core Data'nın 20 yıllık gücünü modern Swift syntax'ı ile birleştiriyor.

İçindekiler

  1. SwiftData Nedir?
  2. Model Tanımlama: @Model Macro
  3. ModelContainer ve ModelContext
  4. CRUD İşlemleri
  5. Queries ve Filtering: @Query Macro
  6. Relationships
  7. Migration Stratejileri
  8. CloudKit Synchronization
  9. Core Data vs SwiftData
  10. Production Best Practices

SwiftData Nedir? {#swiftdata-nedir}

SwiftData, iOS 17+ ile gelen modern persistence framework'ü. Core Data üzerine kurulu ama çok daha basit bir API sunuyor.

Özellik
Core Data
SwiftData
**Model tanımı**
.xcdatamodeld + NSManagedObject
Swift class + @Model
**Query**
NSFetchRequest + NSPredicate
@Query + #Predicate
**Context**
NSManagedObjectContext
ModelContext
**Setup**
30+ satır boilerplate
1 satır: .modelContainer
**SwiftUI**
Manuel entegrasyon
Native entegrasyon

Dış Kaynaklar:


Model Tanımlama: @Model Macro {#model-tanimlama}

swift
1import SwiftData
2 
3// ✅ SwiftData Model - sadece @Model macro yeterli!
4@Model
5final class Task {
6 var title: String
7 var notes: String
8 var isCompleted: Bool
9 var priority: Priority
10 var dueDate: Date?
11 var createdAt: Date
12 
13 // Relationship
14 var category: Category?
15 var tags: [Tag]
16 
17 // Computed property (persist edilmez)
18 var isOverdue: Bool {
19 guard let dueDate else { return false }
20 return !isCompleted && dueDate < Date()
21 }
22 
23 init(title: String, notes: String = "", priority: Priority = .medium) {
24 self.title = title
25 self.notes = notes
26 self.isCompleted = false
27 self.priority = priority
28 self.createdAt = Date()
29 self.tags = []
30 }
31 
32 enum Priority: Int, Codable, CaseIterable {
33 case low = 0, medium = 1, high = 2, critical = 3
34 
35 var label: String {
36 switch self {
37 case .low: return "Düşük"
38 case .medium: return "Orta"
39 case .high: return "Yüksek"
40 case .critical: return "Kritik"
41 }
42 }
43 }
44}
45 
46// @Attribute ile özelleştirme
47@Model
48final class User {
49 @Attribute(.unique) var email: String // Unique constraint
50 var name: String
51 
52 @Attribute(.externalStorage) var profileImage: Data? // Büyük veri dışarıda
53 
54 @Attribute(.transformable(by: URLTransformer.self))
55 var website: URL?
56 
57 @Relationship(deleteRule: .cascade) // Cascade delete
58 var posts: [Post]
59 
60 init(email: String, name: String) {
61 self.email = email
62 self.name = name
63 self.posts = []
64 }
65}

ModelContainer ve ModelContext {#container-context}

swift
1// SwiftUI App'de setup - tek satır!
2@main
3struct MyApp: App {
4 var body: some Scene {
5 WindowGroup {
6 ContentView()
7 }
8 .modelContainer(for: [Task.self, Category.self, Tag.self])
9 }
10}
11 
12// Custom configuration
13let config = ModelConfiguration(
14 "MyAppDB",
15 schema: Schema([Task.self, Category.self]),
16 isStoredInMemoryOnly: false,
17 allowsSave: true,
18 groupContainer: .identifier("group.com.myapp") // App Group
19)
20 
21let container = try ModelContainer(
22 for: Task.self, Category.self,
23 configurations: config
24)

CRUD İşlemleri {#crud}

swift
1struct TaskManagerView: View {
2 @Environment(\.modelContext) private var context
3 
4 // CREATE
5 func addTask(title: String) {
6 let task = Task(title: title, priority: .medium)
7 context.insert(task)
8 // Otomatik save! (autosave enabled by default)
9 }
10 
11 // READ - @Query ile (aşağıda detaylı)
12 
13 // UPDATE - doğrudan property'yi değiştir
14 func toggleComplete(_ task: Task) {
15 task.isCompleted.toggle()
16 // Otomatik save!
17 }
18 
19 // DELETE
20 func deleteTask(_ task: Task) {
21 context.delete(task)
22 }
23 
24 // BATCH DELETE
25 func deleteCompleted() throws {
26 try context.delete(model: Task.self, where: #Predicate {
27 $0.isCompleted == true
28 })
29 }
30}

Queries ve Filtering: @Query Macro {#queries}

swift
1struct TaskListView: View {
2 // Temel query - tüm task'ları getir
3 @Query var allTasks: [Task]
4 
5 // Sıralı query
6 @Query(sort: \Task.createdAt, order: .reverse)
7 var recentTasks: [Task]
8 
9 // Filtrelenmiş query
10 @Query(filter: #Predicate<Task> { $0.isCompleted == false })
11 var activeTasks: [Task]
12 
13 // Karmaşık query
14 @Query(
15 filter: #Predicate<Task> {
16 $0.isCompleted == false &&
17 $0.priority.rawValue >= 2
18 },
19 sort: [
20 SortDescriptor(\Task.priority, order: .reverse),
21 SortDescriptor(\Task.dueDate)
22 ],
23 animation: .default
24 )
25 var urgentTasks: [Task]
26 
27 // Dinamik query
28 init(showCompleted: Bool) {
29 let predicate: Predicate<Task>
30 if showCompleted {
31 predicate = #Predicate { _ in true }
32 } else {
33 predicate = #Predicate { $0.isCompleted == false }
34 }
35 _activeTasks = Query(filter: predicate, sort: \Task.createdAt)
36 }
37 
38 var body: some View {
39 List {
40 ForEach(activeTasks) { task in
41 TaskRow(task: task)
42 }
43 }
44 }
45}

Relationships {#relationships}

swift
1@Model
2final class Category {
3 var name: String
4 var color: String
5 
6 @Relationship(deleteRule: .cascade, inverse: \Task.category)
7 var tasks: [Task]
8 
9 init(name: String, color: String) {
10 self.name = name
11 self.color = color
12 self.tasks = []
13 }
14}
15 
16// Kullanım
17func addTaskToCategory(task: Task, category: Category) {
18 task.category = category
19 // İlişki otomatik kurulur, iki taraf da güncellenir
20}

Migration Stratejileri {#migration}

SwiftData'da schema değişikliklerini yönetmek için VersionedSchema ve SchemaMigrationPlan kullanılır:

swift
1// Versiyon 1 - İlk schema
2enum SchemaV1: VersionedSchema {
3 static var versionIdentifier: Schema.Version = .init(1, 0, 0)
4 static var models: [any PersistentModel.Type] { [TaskV1.self] }
5 
6 @Model final class TaskV1 {
7 var title: String
8 var isCompleted: Bool
9 init(title: String) {
10 self.title = title
11 self.isCompleted = false
12 }
13 }
14}
15 
16// Versiyon 2 - priority field eklendi
17enum SchemaV2: VersionedSchema {
18 static var versionIdentifier: Schema.Version = .init(2, 0, 0)
19 static var models: [any PersistentModel.Type] { [TaskV2.self] }
20 
21 @Model final class TaskV2 {
22 var title: String
23 var isCompleted: Bool
24 var priority: Int // Yeni field!
25 init(title: String, priority: Int = 0) {
26 self.title = title
27 self.isCompleted = false
28 self.priority = priority
29 }
30 }
31}
32 
33// Migration planı tanımla
34enum TaskMigrationPlan: SchemaMigrationPlan {
35 static var schemas: [any VersionedSchema.Type] {
36 [SchemaV1.self, SchemaV2.self]
37 }
38 static var stages: [MigrationStage] { [migrateV1toV2] }
39 
40 static let migrateV1toV2 = MigrationStage.lightweight(
41 fromVersion: SchemaV1.self,
42 toVersion: SchemaV2.self
43 )
44}
45 
46// Container'da migration planını aktif et
47let container = try ModelContainer(
48 for: SchemaV2.TaskV2.self,
49 migrationPlan: TaskMigrationPlan.self
50)

Migration Türleri Karşılaştırma

Migration Türü
Ne Zaman Kullanılır
Örnek
Karmaşıklık
**Lightweight**
Basit schema değişiklikleri
Property ekleme/silme, rename
Düşük
**Custom**
Veri dönüşümü gerektiğinde
Format değişikliği, veri birleştirme
Orta
**Staged**
Çoklu versiyon geçişi
V1 → V2 → V3 zincirleme
Yüksek
⚠️ Migration İpucu: Lightweight migration sadece additive değişiklikler (yeni property, default değerli property) için çalışır. Property tipini değiştirme veya relationship yapısını değiştirme custom migration gerektirir.

CloudKit Synchronization {#cloudkit}

SwiftData, CloudKit ile entegre çalışarak kullanıcı verilerini tüm Apple cihazlarında senkronize eder:

swift
1// CloudKit-enabled container oluştur
2let cloudConfig = ModelConfiguration(
3 cloudKitDatabase: .private("iCloud.com.myapp.data")
4)
5 
6let container = try ModelContainer(
7 for: Task.self, Category.self,
8 configurations: cloudConfig
9)
10 
11// CloudKit uyumlu model kuralları
12@Model
13final class CloudTask {
14 var title: String
15 var notes: String? // Optional olmalı ✅
16 var isCompleted: Bool // Default değer var ✅
17 var category: Category? // Relationship optional ✅
18 var createdAt: Date
19 
20 init(title: String) {
21 self.title = title
22 self.isCompleted = false
23 self.createdAt = Date()
24 }
25}

CloudKit Kuralları ve Limitleri

Kural
Açıklama
Optional property'ler
CloudKit sync için property'ler optional veya default değerli olmalı
@Attribute(.unique) yok
Unique constraint CloudKit ile uyumsuz
Record boyutu
Max 1MB per record
Asset boyutu
Max 250MB per asset
Büyük dosyalar
`@Attribute(.externalStorage)` kullan

Core Data vs SwiftData {#karsilastirma}

swift
1// ❌ Core Data - Çok fazla boilerplate
2let request = NSFetchRequest<TaskEntity>(entityName: "Task")
3request.predicate = NSPredicate(format: "isCompleted == %@ AND priority >= %d", NSNumber(false), 2)
4request.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
5let results = try context.fetch(request)
6let tasks = results.map { $0.toDomain() }
7 
8// ✅ SwiftData - Temiz ve type-safe
9@Query(
10 filter: #Predicate<Task> { !$0.isCompleted && $0.priority.rawValue >= 2 },
11 sort: \Task.createdAt, order: .reverse
12)
13var tasks: [Task]

Production Best Practices {#best-practices}

🔑 Çıkarımlar

  1. @Model ile model tanımla - .xcdatamodeld'e gerek yok
  2. @Query ile SwiftUI'da reactive data fetching
  3. #Predicate ile type-safe filtreleme
  4. Autosave varsayılan - manuel save genelde gereksiz
  5. @Attribute(.unique) ile duplicate önle
  6. Migration için VersionedSchema kullan

Easter Egg

Gizli bir bilgi buldun!

Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?

Okuyucu Ödülü

Tebrikler! Bu yazıyı sonuna kadar okuduğun için sana özel bir hediyem var:

ALTIN İPUCU

Bu yazının en değerli bilgisi

Bu ipucu, yazının en önemli çıkarımını içeriyor.

Etiketler

#swiftdata#core-data#ios-17#persistence#database#swift#tutorial
Muhittin Çamdalı

Muhittin Çamdalı

Senior iOS Developer

12+ yıllık deneyime sahip iOS Developer. Swift, SwiftUI ve modern iOS mimarileri konusunda uzman. Apple platformlarında performanslı ve kullanıcı dostu uygulamalar geliştiriyorum.

iOS Geliştirme Haberleri

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

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.

Paylaş

Bunu da begenebilirsiniz