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 にかなり寄せて簡潔 です。

  1. モデル定義

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 か、という程度です。

  1. フィルタ付き取得

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 に持ち込みやすいです。

  1. 実務上の読み替え

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 や大規模運用 ではまだ強いです。