9148c358d0
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를 Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류. - 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로 자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거, 동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거. - 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming, Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business, Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로, 나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는 title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백). 원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지. - 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서. - 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는 지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지. - Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경. - 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
6.2 KiB
6.2 KiB
id: ios-swiftdata-patterns title: SwiftData — Modern Persistence (iOS 17+) category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [ios, swiftdata, persistence, vibe-coding] tech_stack: { language: "Swift / SwiftData", applicable_to: ["iOS"] } applied_in: [] aliases: [SwiftData, @Model, ModelContainer, ModelContext, query, predicate]
SwiftData (iOS 17+)
Core Data 의 현대적 wrapper.
@Modelmacro + Swift native syntax. SwiftUI 통합. iCloud 동기화 자동. 새 프로젝트 = SwiftData.
📖 핵심 개념
- @Model: persisted class.
- ModelContainer: store.
- ModelContext: 변경 단위 (transaction).
- @Query: SwiftUI 자동 fetch.
💻 코드 패턴
Model
import SwiftData
@Model
final class Note {
@Attribute(.unique) var id: UUID
var title: String
var body: String
var createdAt: Date
@Relationship(deleteRule: .cascade) var tags: [Tag] = []
init(title: String, body: String) {
self.id = UUID()
self.title = title
self.body = body
self.createdAt = Date()
}
}
@Model
final class Tag {
@Attribute(.unique) var name: String
var notes: [Note] = []
init(name: String) { self.name = name }
}
App setup
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: [Note.self, Tag.self])
}
}
SwiftUI — @Query
struct NotesList: View {
@Query(sort: \Note.createdAt, order: .reverse) private var notes: [Note]
@Environment(\.modelContext) private var ctx
var body: some View {
List {
ForEach(notes) { note in
NavigationLink(value: note) {
Text(note.title)
}
}
.onDelete(perform: delete)
}
}
private func delete(at offsets: IndexSet) {
for i in offsets {
ctx.delete(notes[i])
}
}
}
Filter (Predicate)
@Query(filter: #Predicate<Note> { $0.title.contains("Foo") },
sort: \.createdAt, order: .reverse)
var notes: [Note]
// Dynamic
@Query private var notes: [Note]
init(searchText: String) {
let predicate = #Predicate<Note> { $0.title.localizedStandardContains(searchText) }
_notes = Query(filter: predicate, sort: \.createdAt, order: .reverse)
}
CRUD
// Create
let note = Note(title: "Hello", body: "World")
ctx.insert(note)
try ctx.save() // 또는 자동 (SwiftUI)
// Update — 그냥 변경
note.title = "Updated"
try ctx.save()
// Delete
ctx.delete(note)
try ctx.save()
// Fetch (manual)
let descriptor = FetchDescriptor<Note>(
predicate: #Predicate { $0.title.contains("Foo") },
sortBy: [SortDescriptor(\.createdAt, order: .reverse)]
)
let notes = try ctx.fetch(descriptor)
Relationship
let note = Note(title: "...", body: "...")
let tag = Tag(name: "important")
note.tags.append(tag)
ctx.insert(note)
try ctx.save()
// tag 도 자동 insert
Cascade delete
@Relationship(deleteRule: .cascade) var tags: [Tag]
// note 삭제 = tags 도
@Relationship(deleteRule: .nullify) var author: User?
// note 삭제 = user.notes 에서 nullify
iCloud sync (CloudKit)
.modelContainer(for: Note.self, isAutosaveEnabled: true)
// Cloud 자동 sync — Bundle ID + iCloud capability + entitlement
Capabilities → iCloud → CloudKit
+ Background Modes → Remote notifications
→ 사용자가 iCloud 계정만 있으면 자동.
Migration
enum NotesV1: VersionedSchema {
static var versionIdentifier = Schema.Version(1, 0, 0)
static var models: [any PersistentModel.Type] = [Note.self]
}
enum NotesV2: VersionedSchema {
static var versionIdentifier = Schema.Version(2, 0, 0)
static var models: [any PersistentModel.Type] = [Note.self]
}
enum MigrationPlan: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] = [NotesV1.self, NotesV2.self]
static var stages: [MigrationStage] = [
.lightweight(fromVersion: NotesV1.self, toVersion: NotesV2.self),
]
}
let container = try ModelContainer(
for: Note.self,
migrationPlan: MigrationPlan.self
)
Background context
let context = ModelContext(container)
// 또는 동기 — main actor 권장 SwiftUI
// Heavy import
Task.detached {
let bgContext = ModelContext(container)
for item in items {
bgContext.insert(...)
}
try bgContext.save()
}
vs Core Data
SwiftData:
+ 코드 단순, type-safe
+ macro 자동
+ Async/await 친화
- iOS 17+ only
- 일부 advanced 기능 부족 (NSPredicate 만큼)
Core Data:
+ 안정 / 강력
+ 모든 OS
- Boilerplate
- Objc legacy
→ 새 프로젝트 + iOS 17+ = SwiftData.
Performance 팁
- @Query 자동 throttle (UI 안 깨짐).
- Predicate 안 무거운 계산 X.
- 큰 fetch = sortBy / fetchLimit.
- Background context 큰 import.
let descriptor = FetchDescriptor<Note>()
descriptor.fetchLimit = 50
descriptor.fetchOffset = page * 50
Error handling
do {
try ctx.save()
} catch {
log.error("save failed: \(error)")
ctx.rollback()
}
🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| iOS 17+ 새 프로젝트 | SwiftData |
| 기존 Core Data | Core Data 유지 또는 점진 |
| 매우 단순 | UserDefaults / file |
| 큰 / 복잡 query | Core Data + NSFetchRequest |
| Cross-platform (Android) | SQLite + SQLDelight |
| Cloud sync 필요 | SwiftData + CloudKit |
❌ 안티패턴
- Main thread 큰 import: UI freeze. background context.
- @Query 너무 많은 row: limit / pagination.
- Predicate 안 비싼 함수: 매 row evaluation.
- save() 매 변경: batch.
- Migration 무계획: production data 손실.
- Core Data + SwiftData 같은 store: 헷갈림. 한 가지.
- Schema 변경 + lightweight 가정: 복잡 = custom migration.
🤖 LLM 활용 힌트
- @Model + @Query + ModelContext 3종.
- SwiftUI 자동 통합 = 재렌더 자동.
- Migration plan 명시.
- iCloud 자동 sync — capability 켜기.