core-data
iOSアプリでデータを保存するために、データモデルの設計やデータの取得、バックグラウンドでの処理、SwiftDataへの移行などをスムーズに行えるように支援するSkill。
📜 元の英語説明(参考)
Core Data for iOS persistence. Data models, fetch requests, background contexts, and SwiftData migration.
🇯🇵 日本人クリエイター向け解説
iOSアプリでデータを保存するために、データモデルの設計やデータの取得、バックグラウンドでの処理、SwiftDataへの移行などをスムーズに行えるように支援するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o core-data.zip https://jpskill.com/download/16407.zip && unzip -o core-data.zip && rm core-data.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/16407.zip -OutFile "$d\core-data.zip"; Expand-Archive "$d\core-data.zip" -DestinationPath $d -Force; ri "$d\core-data.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
core-data.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
core-dataフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Core Data
Core DataとSwiftDataを使用したiOSの永続化について説明します。
Core Dataスタック
基本的な設定
// ✅ Core Dataスタック
class PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "DataModel")
if inMemory {
container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores { description, error in
if let error = error {
fatalError("Core Data store failed to load: \(error)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
}
var viewContext: NSManagedObjectContext {
container.viewContext
}
func backgroundContext() -> NSManagedObjectContext {
container.newBackgroundContext()
}
}
SwiftUIとの統合
// ✅ SwiftUIでの@FetchRequest
struct UserListView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \User.name, ascending: true)],
animation: .default)
private var users: FetchedResults<User>
var body: some View {
List {
ForEach(users) { user in
Text(user.name ?? "Unknown")
}
.onDelete(perform: deleteUsers)
}
}
private func deleteUsers(offsets: IndexSet) {
withAnimation {
offsets.map { users[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
print("Failed to save: \(error)")
}
}
}
}
フェッチリクエスト
基本的なフェッチ
// ✅ 簡単なフェッチ
func fetchUsers() -> [User] {
let request: NSFetchRequest<User> = User.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
do {
return try viewContext.fetch(request)
} catch {
print("Fetch error: \(error)")
return []
}
}
// ✅ 述語付き
func fetchUsers(named name: String) -> [User] {
let request: NSFetchRequest<User> = User.fetchRequest()
request.predicate = NSPredicate(format: "name == %@", name)
request.fetchLimit = 1
do {
return try viewContext.fetch(request)
} catch {
return []
}
}
// ✅ 複雑な述語
func searchUsers(query: String) -> [User] {
let request: NSFetchRequest<User> = User.fetchRequest()
request.predicate = NSPredicate(
format: "name CONTAINS[cd] %@ OR email CONTAINS[cd] %@",
query, query
)
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
do {
return try viewContext.fetch(request)
} catch {
return []
}
}
バックグラウンドコンテキスト
バックグラウンド処理
// ✅ バックグラウンド書き込みの実行
func saveUser(name: String, email: String) {
let context = PersistenceController.shared.backgroundContext()
context.perform {
let user = User(context: context)
user.name = name
user.email = email
user.createdAt = Date()
do {
try context.save()
} catch {
print("Failed to save: \(error)")
}
}
}
// ✅ バッチ削除
func deleteAllUsers() {
let context = PersistenceController.shared.backgroundContext()
context.perform {
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = User.fetchRequest()
let batchDelete = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try context.execute(batchDelete)
try context.save()
} catch {
print("Batch delete failed: \(error)")
}
}
}
リレーションシップ
リレーションシップのモデリング
// ✅ To-Oneリレーションシップ
extension User {
@NSManaged var department: Department?
}
// ✅ To-Manyリレーションシップ
extension Department {
@NSManaged var employees: NSSet?
var employeesArray: [User] {
let set = employees as? Set<User> ?? []
return set.sorted { $0.name ?? "" < $1.name ?? "" }
}
}
// ✅ リレーションシップによるフェッチ
func fetchUsers(in departmentName: String) -> [User] {
let request: NSFetchRequest<User> = User.fetchRequest()
request.predicate = NSPredicate(format: "department.name == %@", departmentName)
do {
return try viewContext.fetch(request)
} catch {
return []
}
}
SwiftData (iOS 17+)
基本的なSwiftData
// ✅ SwiftDataモデル
@Model
final class User {
var name: String
var email: String
var createdAt: Date
init(name: String, email: String) {
self.name = name
self.email = email
self.createdAt = Date()
}
}
// ✅ SwiftDataの設定
@main
struct MyApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([User.self])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
// ✅ SwiftUIでの@Query
struct UserListView: View {
@Environment(\.modelContext) private var modelContext
@Query(sort: \User.name, order: .forward) private var users: [User]
var body: some View {
List {
ForEach(users) { user in
Text(user.name)
}
.onDelete(perform: deleteUsers)
}
}
private func deleteUsers(offsets: IndexSet) {
withAnimation {
for index in of 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Core Data
iOS persistence with Core Data and SwiftData.
Core Data Stack
Basic Setup
// ✅ Core Data stack
class PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "DataModel")
if inMemory {
container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores { description, error in
if let error = error {
fatalError("Core Data store failed to load: \(error)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
}
var viewContext: NSManagedObjectContext {
container.viewContext
}
func backgroundContext() -> NSManagedObjectContext {
container.newBackgroundContext()
}
}
SwiftUI Integration
// ✅ @FetchRequest in SwiftUI
struct UserListView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \User.name, ascending: true)],
animation: .default)
private var users: FetchedResults<User>
var body: some View {
List {
ForEach(users) { user in
Text(user.name ?? "Unknown")
}
.onDelete(perform: deleteUsers)
}
}
private func deleteUsers(offsets: IndexSet) {
withAnimation {
offsets.map { users[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
print("Failed to save: \(error)")
}
}
}
}
Fetch Requests
Basic Fetch
// ✅ Simple fetch
func fetchUsers() -> [User] {
let request: NSFetchRequest<User> = User.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
do {
return try viewContext.fetch(request)
} catch {
print("Fetch error: \(error)")
return []
}
}
// ✅ With predicate
func fetchUsers(named name: String) -> [User] {
let request: NSFetchRequest<User> = User.fetchRequest()
request.predicate = NSPredicate(format: "name == %@", name)
request.fetchLimit = 1
do {
return try viewContext.fetch(request)
} catch {
return []
}
}
// ✅ Complex predicate
func searchUsers(query: String) -> [User] {
let request: NSFetchRequest<User> = User.fetchRequest()
request.predicate = NSPredicate(
format: "name CONTAINS[cd] %@ OR email CONTAINS[cd] %@",
query, query
)
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
do {
return try viewContext.fetch(request)
} catch {
return []
}
}
Background Context
Background Operations
// ✅ Perform background write
func saveUser(name: String, email: String) {
let context = PersistenceController.shared.backgroundContext()
context.perform {
let user = User(context: context)
user.name = name
user.email = email
user.createdAt = Date()
do {
try context.save()
} catch {
print("Failed to save: \(error)")
}
}
}
// ✅ Batch delete
func deleteAllUsers() {
let context = PersistenceController.shared.backgroundContext()
context.perform {
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = User.fetchRequest()
let batchDelete = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try context.execute(batchDelete)
try context.save()
} catch {
print("Batch delete failed: \(error)")
}
}
}
Relationships
Modeling Relationships
// ✅ To-One relationship
extension User {
@NSManaged var department: Department?
}
// ✅ To-Many relationship
extension Department {
@NSManaged var employees: NSSet?
var employeesArray: [User] {
let set = employees as? Set<User> ?? []
return set.sorted { $0.name ?? "" < $1.name ?? "" }
}
}
// ✅ Fetch with relationship
func fetchUsers(in departmentName: String) -> [User] {
let request: NSFetchRequest<User> = User.fetchRequest()
request.predicate = NSPredicate(format: "department.name == %@", departmentName)
do {
return try viewContext.fetch(request)
} catch {
return []
}
}
SwiftData (iOS 17+)
Basic SwiftData
// ✅ SwiftData model
@Model
final class User {
var name: String
var email: String
var createdAt: Date
init(name: String, email: String) {
self.name = name
self.email = email
self.createdAt = Date()
}
}
// ✅ SwiftData setup
@main
struct MyApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([User.self])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(for: schema, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
// ✅ @Query in SwiftUI
struct UserListView: View {
@Environment(\.modelContext) private var modelContext
@Query(sort: \User.name, order: .forward) private var users: [User]
var body: some View {
List {
ForEach(users) { user in
Text(user.name)
}
.onDelete(perform: deleteUsers)
}
}
private func deleteUsers(offsets: IndexSet) {
withAnimation {
for index in offsets {
modelContext.delete(users[index])
}
}
}
}
SwiftData Predicates
// ✅ #Predicate macro
@Query(filter: #Predicate<User> { user in
user.name.contains("John") && user.createdAt > Date().addingTimeInterval(-86400)
})
var recentJohns: [User]
// ✅ Dynamic predicate
struct UserListView: View {
@State private var searchText = ""
var body: some View {
UserList(searchText: searchText)
}
}
struct UserList: View {
let searchText: String
var predicate: Predicate<User> {
#Predicate<User> { user in
user.name.contains(searchText)
}
}
var body: some View {
@Query(filter: predicate) var users: [User]
List(users) { user in
Text(user.name)
}
}
}
Migration
Lightweight Migration
let description = NSPersistentStoreDescription(url: storeURL)
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
Migration Strategy
// ✅ Custom mapping model
func migrateStore(at sourceURL: URL, to destinationURL: URL) {
let migrationManager = NSMigrationManager(
sourceStoreAt: sourceURL,
destinationStoreAt: destinationURL
)
do {
try migrationManager.migrateStore(
from: sourceURL,
sourceType: NSSQLiteStoreType,
with: nil,
to: destinationURL,
destinationType: NSSQLiteStoreType
)
} catch {
print("Migration failed: \(error)")
}
}
Best Practices
// ✅ Use background context for writes
func batchInsert(items: [Item]) {
let context = backgroundContext()
context.perform {
for item in items {
let managedItem = Item(context: context)
managedItem.name = item.name
}
try? context.save()
}
}
// ✅ Batch fetch for large datasets
func fetchAllUsersEfficiently() -> [User] {
let request = NSFetchRequest<User>(entityName: "User")
request.returnsObjectsAsFaults = false
request.fetchBatchSize = 100
return try! viewContext.fetch(request)
}
// ❌ Don't block main thread
// ❌ Bad: Fetching on main thread with large data
let users = viewContext.fetch(largeRequest) // Blocks UI
// ✅ Good: Background fetch
let context = backgroundContext()
context.perform {
let users = try! context.fetch(largeRequest)
DispatchQueue.main.async {
// Update UI with results
}
}
Remember: Core Data is powerful but complex. Use it for complex data models, consider SwiftData for new projects.