Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SwiftDataを使って10万件のデータを読み書きする

Avatar for akidon0000 akidon0000
October 18, 2025

 SwiftDataを使って10万件のデータを読み書きする

yidev 第29回勉強会 — 第3部の追加開催回
https://yidev3.connpass.com/event/366947/

Avatar for akidon0000

akidon0000

October 18, 2025
Tweet

More Decks by akidon0000

Other Decks in Programming

Transcript

  1. BLJEPO γϯϓϧͳ-JTUͷ࣮૷ import SwiftData @Model class SimpleObject { @Attribute(.unique) var

    id: String var name: String var creationDate: Date } ɾ.PEFMͷ࣮૷ ɾ.PEFM$POUBJOFS ɾ.PEFM$POUFYU ɾσʔλͷ௥Ճ ɾ!2VFSZ
  2. BLJEPO γϯϓϧͳ-JTUͷ࣮૷ import SwiftData @Model class SimpleObject { @Attribute(.unique) var

    id: String var name: String var creationDate: Date init(name: String = "", createdAt: Date = .now) { self.id = UUID().uuidString self.name = name self.creationDate = createdAt } } ɾ.PEFMͷ࣮૷ ɾ.PEFM$POUBJOFS ɾ.PEFM$POUFYU ɾσʔλͷ௥Ճ ɾ!2VFSZ
  3. BLJEPO γϯϓϧͳ-JTUͷ࣮૷ import SwiftData let container = try ModelContainer(for: [SimpleObject.self])

    ɾ.PEFMͷ࣮૷ ɾ.PEFM$POUBJOFS ɾ.PEFM$POUFYU ɾσʔλͷ௥Ճ ɾ!2VFSZ
  4. BLJEPO γϯϓϧͳ-JTUͷ࣮૷ import SwiftData import SwiftUI @main struct SwiftDataSampleApp: App

    { var body: some Scene { WindowGroup { SimpleObjectListView() } .modelContainer(for: [SimpleObject.self]) } } ɾ.PEFMͷ࣮૷ ɾ.PEFM$POUBJOFS ɾ.PEFM$POUFYU ɾσʔλͷ௥Ճ ɾ!2VFSZ
  5. BLJEPO γϯϓϧͳ-JTUͷ࣮૷ import SwiftData import SwiftUI struct SimpleObjectListView: View {

    @Environment(\.modelContext) private var modelContext } ɾ.PEFMͷ࣮૷ ɾ.PEFM$POUBJOFS ɾ.PEFM$POUFYU ɾσʔλͷ௥Ճ ɾ!2VFSZ
  6. BLJEPO γϯϓϧͳ-JTUͷ࣮૷ var object = SimpleObject(name: “akidon") // ... modelContext.insert(object)

    try modelContext.save() ɾ.PEFMͷ࣮૷ ɾ.PEFM$POUBJOFS ɾ.PEFM$POUFYU ɾσʔλͷ௥Ճ ɾ!2VFSZ
  7. BLJEPO γϯϓϧͳ-JTUͷ࣮૷ import SwiftData import SwiftUI struct SimpleObjectListView: View {

    @Environment(\.modelContext) private var modelContext @Query(sort: \SimpleObject.name, order: .forward) private var simpleObjects: [SimpleObject] var body: some View { List { ForEach(simpleObjects) { object in Text(object.name) } } } } ɾ.PEFMͷ࣮૷ ɾ.PEFM$POUBJOFS ɾ.PEFM$POUFYU ɾσʔλͷ௥Ճ ɾ!2VFSZ
  8. BLJEPO ݕࡧͷ࣮૷ @Query(sort: \SimpleObject.name, order: .forward) private var simpleObjects: [SimpleObject]

    @State private var searchText: String = “" var searchResults: [SimpleObject] { if searchText.isEmpty { return simpleObjects } else { return simpleObjects.filter { $0.name.contains(searchText) } } } var body: some View { List { ForEach(searchResults) { object in Text(object.name) } } .searchable(text: $searchText) }
  9. BLJEPO ݕࡧͷ࣮૷ @Query(sort: \SimpleObject.name, order: .forward) private var simpleObjects: [SimpleObject]

    @State private var searchText: String = “" var searchResults: [SimpleObject] { if searchText.isEmpty { return simpleObjects } else { return simpleObjects.filter { $0.name.contains(searchText) } } } var body: some View { List { ForEach(searchResults) { object in Text(object.name) } } .searchable(text: $searchText) } 4JNQMF0CKFDUΛશͯϑΣονͯ͠ΔͨΊ %#ݕࡧΑΓ fi MUFSͷํ͕ߴ଎
  10. BLJEPO ΠϯσοΫεϥϕϧػೳͷ࣮૷ var body: some View { List { ForEach(sections,

    id: \.key) { section in Section(header: Text(section.key)) { ForEach(section.items) { item in Text(item.name) } } .sectionIndexLabel(section.key) } } .searchable(text: $searchText) }
  11. BLJEPO ສ݅ͷॻ͖ࠐΈ for _ in 0..<count { let object =

    SimpleObject(name: "akidon") modelContext.insert(object) } try modelContext.save() ˞.BJO5ISFBE
  12. BLJEPO ສ݅ͷॻ͖ࠐΈ for _ in 0..<count { let object =

    SimpleObject(name: "akidon") modelContext.insert(object) } try modelContext.save()
  13. BLJEPO όοΫάϥ΢ϯυͰॻ͖ࠐΉ import Foundation import SwiftData @ModelActor actor SimpleObjectActor {

    func fetchAllData() throws -> [SimpleObject] { var descriptor = FetchDescriptor<SimpleObject>( sortBy: [SortDescriptor(\SimpleObject.name, order: .forward)] ) return try modelContext.fetch(descriptor) } func insert(items: [SimpleObject]) throws { _ = items.map { modelContext.insert($0) } try modelContext.save() } func deleteAll() throws { try modelContext.delete(model: SimpleObject.self) } }
  14. BLJEPO $PNQMFY0CKFDU @Model class School { @Attribute(.unique) var id: String

    var name: String var location: String @Relationship(deleteRule: .cascade) var students: [Student] } @Model class Student { @Attribute(.unique) var id: String var firstName: String var surname: String var age: Int @Relationship(inverse: \School.students) var school: School? @Relationship(deleteRule: .cascade) var grades: [Grade] } @Model class Grade { @Attribute(.unique) var id: String var subject: String var grade: String var examBoard: String @Relationship(inverse: \Student.grades) var student: Student? } ˞ࡶʹ࡞ͬͨͷͰؒҧͬͯΔ͔΋
  15. BLJEPO ແݶεΫϩʔϧ var body: some View { List { ForEach(simpleObjects.enumerated(),

    id: \.element.id) { index, object in Text(object.name) .onAppear { let listCount = self.simpleObjects.count if index >= listCount - 1 { var descriptor = FetchDescriptor<SimpleObject>( sortBy: [SortDescriptor(\SimpleObject.name, order: .forward)] ) descriptor.fetchOffset = listCount descriptor.fetchLimit = 50 Task { guard let nextLists = try? modelContext.fetch(descriptor) else { return } await MainActor.run { simpleObjects.append(contentsOf: nextLists) } } } } } } .scrollIndicators(.hidden) }
  16. BLJEPO ແݶεΫϩʔϧ var body: some View { List { ForEach(simpleObjects.enumerated(),

    id: \.element.id) { index, object in Text(object.name) .onAppear { let listCount = self.simpleObjects.count if index >= listCount - 1 { var descriptor = FetchDescriptor<SimpleObject>( sortBy: [SortDescriptor(\SimpleObject.name, order: .forward)] ) descriptor.fetchOffset = listCount descriptor.fetchLimit = 50 Task { guard let nextLists = try? modelContext.fetch(descriptor) else { return } await MainActor.run { simpleObjects.append(contentsOf: nextLists) } } } } } } .scrollIndicators(.hidden) } εΫϩʔϧόʔ͸࣮ࡍͷϖʔδͷ௕͞Λ ൓ө͢Δ΂͖ͳͷͰඇදࣔ
  17. BLJEPO ແݶεΫϩʔϧ ݕࡧόʔ private func searchSimpleObjectsInStore(for searchText: String) { let

    predicate = #Predicate<SimpleObject> { school in school.name.starts(with: searchText) } let descriptor = FetchDescriptor<SimpleObject>( predicate: predicate, sortBy: [SortDescriptor(\SimpleObject.name, order: .forward)] ) Task { guard let searchedLists = try? modelContext.fetch(descriptor) else { return } await MainActor.run { simpleObjects = searchedLists } } }
  18. BLJEPO 4XJGU%BUBͷ෼͔Βͳ͍ͱ͜Ζʂʂ var descriptor = FetchDescriptor<SimpleObject>( sortBy: [SortDescriptor(\SimpleObject.name, order: .forward)]

    ) #Index<SimpleObject>([\SimpleObject.name]) ΠϯσοΫεΛష͍ͬͯͯ΋ɺɺɺ શ݅ιʔτͯ͠औಘͷ৔߹Ͱ͸ɺϑΣον଎౓͸షΔલͱมΘΒͳ͍ ͜ͷTPSU#Z͸%#͔Βશ݅औಘͨ͠ޙʹιʔτͯ͠ΔͷͰ͸ʁ 🤔 લํݕࡧ͢ΔͱΠϯσοΫεͷՁ஋͸ൃش͕ͨ͠ɺ୹ॖ࣌ؒ͸ఔ౓ )%Ͱ͸ແ͘ͳ͔ͬͨΒɺͦ΋ͦ΋଎͍
  19. BLJEPO ࠷ޙʹ͖͋ͲΜͷࢥ͍ w ࠓޙͷൃలͰɺϝϞϦͷಡΈॻ͖εϐʔυɺ$16ͷॲཧ଎౓͔޲্͠.BJO5ISFBEͰ ࣮ߦͯ͠΋໰୊ͳ͍͕࣌͘ΔͷͰ͸ w ϜʔΞͷ๏ଇͩͱݶքΒ͍͕͠ ࠓ͸ϓϩηοαճ࿏͕ݪࢠݸ෼ͷ෯  w

    Ͳ͜Ͱ΋ωοτϫʔΫʹ઀ଓͰ͖ɺΦϑϥΠϯʹͳΔঢ়ଶ͕೔ৗͰ͸ଘࡏ͠ͳ͘ͳ Δ͕࣌͘ΔͷͰ͸ w $BMM%JSFDUPSZ&YUFOTJPO΋ηΩϡϦςΟతͳ໰୊Ͱ-PDBM%#͔͠ڐՄ͍ͯ͠ͳ ͍ͱߟ͑Δ