CoreDataとSwiftDataの比較
Apple の現行ドキュメントベースで整理すると、Core Data は長年使われて きた汎用的で成熟した永続化フレームワーク、SwiftData はそれをより Swift / SwiftUI 向けに書きやすくした新しい永続化フレームワークです。 結論を先に言うと、UIKit/AppKit を含む既存資産や細かい制御が必要なら Core Data、新規の SwiftUI 中心アプリで素直に書きたいなら SwiftData が基本です。
全体比較
| 観点 | Core Data | SwiftData |
|---|---|---|
| 位置づけ | 伝統的な Apple の永続化・オブジェクトグラフ管理 | ネイティブな新しい永続化 API |
| 主な対象 | UIKit/AppKit/SwiftUI すべて、既存資産が多い案件 | SwiftUI 中心の新規実装 |
| モデル定義 | .xcdatamodeld と NSManagedObject が中心 | @Model を付けた Swift の型が中心 |
| 記述スタイル | 宣言ファイル + ランタイム API | Swift コード中心、マクロ活用 |
| コンテキスト | NSManagedObjectContext | ModelContext |
| コンテナ | NSPersistentContainer / NSPersistentCloudKitContainer | ModelContainer |
| 取得 | NSFetchRequest、NSFetchedResultsController | FetchDescriptor、@Query |
| UI 連携 | UIKit/SwiftUI 両対応だがやや手数多め | SwiftUI 統合が強い |
| 自動保存 | 基本は明示的 save() | autosave あり。必要なら明示 save() も可能 |
| マイグレーション | 軽量/手動/段階的移行など成熟 | 自動移行 + 必要に応じて SchemaMigrationPlan |
| 学習コスト | 高め | 低め |
| 細かい制御 | 強い | シンプルだが抽象度高め |
| 既存アプリ移行 | そのまま継続しやすい | 共存・段階移行が可能 |
実装方法の違い
Core Data はモデルエディタでスキーマを定義し、NSManagedObject 系のク ラスを扱います。 保存・取得は NSManagedObjectContext、NSFetchRequest、 NSPersistentContainer などの API を明示的に使う構成です。
let item = Item(context: viewContext) item.timestamp = Date() try viewContext.save()
SwiftData は Swift のクラス自体をモデルとして書きます。@Model で宣言 し、ModelContext に insert、SwiftUI では @Query で一覧取得します。
@Model
final class Item {
var timestamp: Date
init(timestamp: Date) {
self.timestamp = timestamp
}
}
@Environment(\.modelContext) private var modelContext
@Query(sort: \Item.timestamp) private var items: [Item]
let item = Item(timestamp: .now)
modelContext.insert(item)
try modelContext.save()
仕様面の違い
Core Data の強み:
- モデル版管理、軽量/手動/段階的マイグレーションが成熟
- undo/redo、背景処理、大規模データ、複数ストアなどの実績が厚い
- NSFetchedResultsController など、UIKit 向け周辺機能が強い
- 細かいストア設定や既存システムとの統合に向く
SwiftData の強み:
- モデル定義が Swift コードだけで完結しやすい
- SwiftUI で modelContainer、modelContext、@Query を使って自然につな がる
- @Attribute、@Relationship、#Index、#Unique などで宣言的に書ける
- autosave や環境注入により、初期実装がかなり軽い
取得・クエリの違い
Core Data:
- NSFetchRequest
- ソートや predicate を組み立てる
- UIKit では NSFetchedResultsController が定番
SwiftData:
- FetchDescriptor
- SwiftUI では @Query
- Predicate と SortDescriptor ベースで比較的書きやすい
つまり、一覧表示中心の SwiftUI 画面では SwiftData の方がかなり簡潔で す。
保存タイミングの違い
Core Data:
- 基本は save() を自分で呼ぶ前提
- 保存境界を明示したいときに分かりやすい
SwiftData:
- デフォルトで autosave が有効
- ただし確実な保存境界が必要なら save() や transaction {} を使う
このため、簡単な CRUD は SwiftData が楽ですが、保存タイミングを厳密 に制御したい場合は Core Data の感覚の方が扱いやすいことがあります。
マイグレーションの違い
Core Data:
- 古くからあるため移行機構がかなり成熟
- 複雑なスキーマ変更にも対応しやすい
SwiftData:
- 自動移行あり
- 複雑な変更では SchemaMigrationPlan を定義
- 新しい分、実戦ノウハウは Core Data より少なめ
並行処理・バックグラウンド処理
Core Data:
- バックグラウンドコンテキストや競合解決などの実績が豊富
- 大量データ投入や複雑な同期処理に強い
SwiftData:
- ModelContext を使ったよりモダンな API
- ただし複雑なケースでは Core Data の方が情報量・実績ともに多い
CloudKit / 同期
両方とも CloudKit 連携の道があります。 Apple ドキュメント上は、Core Data は NSPersistentCloudKitContainer、 SwiftData は ModelContainer 側で自動同期を扱う形です。 新規 SwiftUI アプリでは SwiftData の方が体験は自然ですが、既存運用や 詳細制御では Core Data が強いです。
既存アプリとの相性
Core Data が向くケース:
- 既存の Core Data アプリ
- UIKit 中心
- 複雑な migration や背景処理が多い
- 大規模運用で安定性重視
SwiftData が向くケース:
- 新規 SwiftUI アプリ
- 小〜中規模で CRUD 中心
- モデル定義を Swift コードに寄せたい
- 学習コストを下げたい
移行の考え方
Apple は Core Data と SwiftData の共存 を案内しています。 つまり全面移行しかないわけではなく、段階移行も可能です。既存 Core Data アプリに SwiftData を一部導入する設計も現実的です。
実務上の判断
- 新規の SwiftUI アプリ: まず SwiftData を検討
- 既存 Core Data アプリ: 無理に全面移行しない
- 複雑な移行や大量データ運用: Core Data 優勢
- まず動くものを素早く作る: SwiftData 優勢
あなたの alerm-ios のような SwiftUI + MVVM + SwiftData 前提の小さめ アプリなら、現時点では SwiftData の選択はかなり自然です。
参考:
- Apple Core Data: https://developer.apple.com/documentation/coredata
- Apple SwiftData ModelContainer: https://developer.apple.com/documentation/swiftdata/modelcontainer
- Apple SwiftData Query: https://developer.apple.com/documentation/swiftdata/query
- Apple “Adopting SwiftData for a Core Data app”:
https://developer.apple.com/documentation/coredata/adopting-swiftdata-for-a-core-data-app
- Apple WWDC23 “Meet SwiftData”: https://developer.apple.com/videos/play/wwdc2023/10187/
同じ CRUD を題材にして、Core Data と SwiftData の書き方の差が見える 形で並べます。まずはモデル定義、次に一覧取得、追加・削除、最後に実務 上の読み替えを整理します。
• 同じ「Item を保存して一覧表示し、追加・削除する」例で並べると差が見 えやすいです。 結論だけ先に言うと、Core Data は構成要素が多く明示的、SwiftData は SwiftUI にかなり寄せて簡潔 です。
- モデル定義
Core Data は通常 .xcdatamodeld で Entity を定義し、必要なら NSManagedObject サブクラスを持ちます。
import CoreData
@objc(Item)
public final class Item: NSManagedObject {
@NSManaged public var timestamp: Date?
}
extension Item {
@nonobjc public class func fetchRequest() ->
NSFetchRequest<Item> {
NSFetchRequest<Item>(entityName: "Item")
}
}
SwiftData は Swift の型に @Model を付けます。
import SwiftData
@Model
final class Item {
var timestamp: Date
init(timestamp: Date) {
self.timestamp = timestamp
}
}
差分:
- Core Data はモデルエディタ前提になりやすい
- SwiftData はコードだけで完結しやすい
- Core Data は optional が増えやすい
-
SwiftData は普通の Swift クラスとして書きやすい
-
コンテナ初期化
Core Data
import SwiftUI
import CoreData
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "alerm")
container.loadPersistentStores { _, error in
if let error {
fatalError("Unresolved error: \(error)")
}
}
container.viewContext.automaticallyMergesChangesFromParent =
true
}
}
@main
struct MyApp: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext,
persistenceController.container.viewContext)
}
}
}
SwiftData
import SwiftUI
import SwiftData
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: Item.self)
}
}
差分:
- Core Data は NSPersistentContainer を自前で組むことが多い
- SwiftData は .modelContainer(for:) でかなり短い
-
SwiftUI への注入も SwiftData の方が自然
-
一覧取得
Core Data
import SwiftUI
import CoreData
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp,
ascending: true)],
animation: .default
)
private var items: FetchedResults<Item>
var body: some View {
List {
ForEach(items) { item in
Text(item.timestamp?.formatted() ?? "")
}
}
}
}
SwiftData
import SwiftUI
import SwiftData
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query(sort: \Item.timestamp, order: .forward)
private var items: [Item]
var body: some View {
List {
ForEach(items) { item in
Text(item.timestamp.formatted())
}
}
}
}
差分:
- Core Data は @FetchRequest
- SwiftData は @Query
- SwiftData は戻り値が普通の [Item] で扱いやすい
-
Core Data は FetchedResults
- を扱う
-
追加
Core Data
private func addItem() {
let newItem = Item(context: viewContext)
newItem.timestamp = Date()
do {
try viewContext.save()
} catch {
print(error.localizedDescription)
}
}
SwiftData
private func addItem() {
let newItem = Item(timestamp: Date())
modelContext.insert(newItem)
do {
try modelContext.save()
} catch {
print(error.localizedDescription)
}
}
差分:
- Core Data は Item(context:)
- SwiftData は普通に init
-
SwiftData の方がモデル生成が自然な Swift に近い
-
削除
Core Data
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { items[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
print(error.localizedDescription)
}
}
}
SwiftData
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { items[$0] }.forEach(modelContext.delete)
do {
try modelContext.save()
} catch {
print(error.localizedDescription)
}
}
}
ここはかなり似ています。 違いは viewContext か modelContext か、という程度です。
- フィルタ付き取得
Core Data
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp,
ascending: false)],
predicate: NSPredicate(format: "timestamp > %@",
Date.distantPast as NSDate)
)
private var items: FetchedResults<Item>
SwiftData
@Query(
filter: #Predicate<Item> { item in
item.timestamp > Date.distantPast
},
sort: \Item.timestamp,
order: .reverse
)
private var items: [Item]
差分:
- Core Data は NSPredicate の文字列や Objective-C 由来 API が出やす い
-
SwiftData は #Predicate で Swift らしく書ける
-
リレーション定義
Core Data
- .xcdatamodeld 上で to-one / to-many を定義
- コード側は NSSet? や生成コードを扱うことが多い
例:
@NSManaged public var alarms: NSSet?
SwiftData
@Model
final class User {
var name: String
@Relationship(deleteRule: .cascade, inverse: \Alarm.owner)
var alarms: [Alarm] = []
init(name: String) {
self.name = name
}
}
@Model
final class Alarm {
var time: Date
var owner: User?
init(time: Date, owner: User? = nil) {
self.time = time
self.owner = owner
}
}
差分:
- SwiftData は配列で扱えて読みやすい
-
Core Data は生成コードや optional collection が絡みやすい
-
ViewModel で使うときの感覚
Core Data
final class ItemListViewModel: ObservableObject {
private let context: NSManagedObjectContext
init(context: NSManagedObjectContext) {
self.context = context
}
func addItem() throws {
let item = Item(context: context)
item.timestamp = .now
try context.save()
}
}
SwiftData
final class ItemListViewModel: ObservableObject {
private let context: ModelContext
init(context: ModelContext) {
self.context = context
}
func addItem() throws {
let item = Item(timestamp: .now)
context.insert(item)
try context.save()
}
}
MVVM での差分は小さいですが、SwiftData の方が model 自体が plain Swift object に近いので ViewModel に持ち込みやすいです。
- 実務上の読み替え
Core Data でよく見るものと SwiftData の対応はだいたいこうです。
- NSManagedObject → @Model
- NSPersistentContainer → ModelContainer
- NSManagedObjectContext → ModelContext
- @FetchRequest → @Query
- NSFetchRequest → FetchDescriptor
- NSSortDescriptor → SortDescriptor
-
NSPredicate → #Predicate
-
どちらが書きやすいか
小さい SwiftUI アプリなら、同じ CRUD でも SwiftData の方がかなり短く なります。 特に以下の差が大きいです。
- モデルを .xcdatamodeld ではなく Swift コードで書ける
- @Query がそのまま SwiftUI の一覧表示につながる
- NSManagedObject 特有の癖が減る
一方で Core Data は、
- 細かい制御
- 古い資産との互換
- 複雑な migration や大規模運用 ではまだ強いです。