Section 2/181 menit

2. Masalah yang Dipecahkan di Level Lanjutan

2. Masalah yang Dipecahkan di Level Lanjutan

Data Duplikat saat CloudKit Sync

swift
// ❌ TANPA @Attribute(.unique): import berulang membuat duplikat
@Model
class Article {
    var remoteID: String  // ID dari server — tidak di-enforce unik
    var title: String
    
    init(remoteID: String, title: String) {
        self.remoteID = remoteID
        self.title = title
    }
}

// Kalau sync berjalan 2x, ada 2 Article dengan remoteID sama
func importArticles(_ articles: [ArticleDTO]) {
    for dto in articles {
        let article = Article(remoteID: dto.id, title: dto.title)
        modelContext.insert(article)  // Duplikat jika sudah ada!
    }
}
swift
// ✓ DENGAN @Attribute(.unique): SwiftData enforce uniqueness + upsert otomatis
@Model
class Article {
    @Attribute(.unique) var remoteID: String  // Jika ada duplikat → update, tidak insert baru
    var title: String
    var body: String
    
    init(remoteID: String, title: String, body: String) {
        self.remoteID = remoteID
        self.title = title
        self.body = body
    }
}

// Insert dengan unique attribute = upsert otomatis
func importArticles(_ articles: [ArticleDTO]) {
    for dto in articles {
        let article = Article(remoteID: dto.id, title: dto.title, body: dto.body)
        modelContext.insert(article)  // Jika remoteID sudah ada → update propertinya
    }
    try? modelContext.save()
}

Predicate Gagal Compile untuk Query Kompleks

swift
// ❌ TANPA pemahaman predicate lanjutan: runtime crash atau compile error
@Query(filter: #Predicate<Task> { task in
    // Ini crash saat runtime karena SwiftData tidak bisa translate ke SQL
    task.tags.contains { $0.name.hasPrefix("important") }
})
var importantTasks: [Task]
swift
// ✓ DENGAN subquery predicate yang benar
@Query(filter: #Predicate<Task> { task in
    task.tags.contains { tag in
        tag.name == "important" || tag.name == "urgent"
    }
})
var importantTasks: [Task]

Migration Gagal karena Tidak Ada Schema Versioning

swift
// ❌ TANPA VersionedSchema: mengganti nama property langsung = crash
@Model
class User {
    // Awalnya: var name: String
    var fullName: String  // Rename tanpa migration → data hilang atau crash!
}
swift
// ✓ DENGAN VersionedSchema + SchemaMigrationPlan: migration aman dan terdokumentasi
enum AppSchemaV1: VersionedSchema {
    static var versionIdentifier = Schema.Version(1, 0, 0)
    static var models: [any PersistentModel.Type] { [UserV1.self] }
    
    @Model final class UserV1 {
        var name: String
        init(name: String) { self.name = name }
    }
}

enum AppSchemaV2: VersionedSchema {
    static var versionIdentifier = Schema.Version(2, 0, 0)
    static var models: [any PersistentModel.Type] { [UserV2.self] }
    
    @Model final class UserV2 {
        var fullName: String
        init(fullName: String) { self.fullName = fullName }
    }
}