CoreData + SwiftUI

May 01 2023
คุณสามารถดูบทความต้นฉบับได้ที่นี่ เมื่อเร็ว ๆ นี้ฉันต้องสร้างแอปโดยใช้ SwiftUI และ CoreData ฉันคิดว่า CoreData เกือบจะเหมือนกับที่คุณใช้กับ UIKit แต่เห็นได้ชัดว่ามีข้อแตกต่างบางประการ
ภาพถ่ายโดย Michael Dziedzic บน Unsplash

คุณสามารถดูบทความต้นฉบับได้ที่นี่

เมื่อ เร็วๆ นี้ฉันต้องสร้างแอปโดยใช้SwiftUIและCoreData

ฉันคิดว่า CoreData เกือบจะเหมือนกับที่คุณใช้กับ UIKit แต่เห็นได้ชัดว่ามีข้อแตกต่างบางประการ

คู่มือนี้มีจุดมุ่งหมายเพื่อสรุปประสบการณ์การใช้ CoreData ร่วมกับ SwiftUI หากฉันพบแง่มุมอื่นๆ ฉันจะเพิ่มลงในคู่มือนี้

ดังนั้นเรามาเริ่มกันโดยไม่ต้องกังวลใจอีกต่อไป

ติดตั้ง

นี่เป็นส่วนที่ค่อนข้างตรงไปตรงมา

  • หากคุณเริ่มโครงการใหม่ คุณสามารถทำเครื่องหมายที่ตัวเลือก ' ใช้ข้อมูลหลัก ' และ ' โฮสต์ใน CloudKit ' หากคุณต้องการบันทึกข้อมูลผู้ใช้ของคุณไปยังคลาวด์ ในกรณีนี้ XCode จะดูแลการตั้งค่าโครงการให้คุณ (สำหรับส่วน CloudKit จะต้องทำขั้นตอนเพิ่มเติม)
  • หากคุณมีโปรเจ็กต์อยู่แล้ว คุณจะต้องสร้าง ไฟล์ Persistence.swiftและไฟล์ swift ที่คุณเริ่มต้นสแต็ก CoreData (คุณสามารถสร้างโครงการใหม่ตามขั้นตอนก่อนหน้า และคัดลอก ไฟล์ Persistence.swiftที่สร้างโดย XCode ไปยังโครงการของคุณ

ตอนนี้คุณมีโปรเจ็กต์แล้ว เพื่อให้สามารถใช้ CoreData ภายใน Views ของคุณได้ คุณจะต้องผ่านลำดับmanagedObjectContextชั้นของ View ลงมา

โดยปกติจะทำในไฟล์[ชื่อแอป] App.swift ของคุณ

PersistenceController ( นี่คือตัวอย่าง ) เป็นโครงสร้างที่ XCode สร้างให้คุณโดยอัตโนมัติเมื่อคุณเริ่มโครงการใหม่โดยเลือกตัวเลือก 'ใช้ข้อมูลหลัก'

@main
struct ExampleApp: App {

  let persistenceController = PersistenceController.shared

  var body: some Scene {
    WindowGroup {
      ContentView()
        .environmentObject(persistenceController)
        .environment(\.managedObjectContext, persistenceController.container.viewContext)
    }
  }
}

เยี่ยมมาก ตอนนี้คุณสามารถสร้าง อ่าน อัปเดต และลบ NSManagedObjects ในมุมมองของคุณได้แล้ว

การทำงานกับ CoreData

ในการใช้งาน CoreData คุณต้องเข้าถึงNSManagedObjectContext ในการทำเช่นนั้น คุณมีสองตัวเลือก:

  • การใช้ @ Environment wrapper ในมุมมองของคุณ
  • @Environment(\.managedObjectContext) private var viewContext
    

    @EnvironmentObject private var persistenceController: PersistenceController
    

do {
  if container.viewContext.hasChanges {
    try container.viewContext.save()
  }
} catch {
  print(error)
}

ในการบันทึก NSManagedObject คุณต้องสร้างอินสแตนซ์ก่อนแล้วจึงกำหนดค่าคุณสมบัติของมัน แล้วบันทึกบริบท

let note = Note(context: container.viewContext)
note.id = id
note.text = text
note.folder = folder
note.creationDate = Date()
saveContext()

กำลังดึงวัตถุ

ตอนนี้ส่วนที่ดึงข้อมูล นี่คือจุดที่ฉันพบปัญหามากที่สุด เริ่มกันเลย

ในการดึงวัตถุใน SwiftUI วิธีที่สะดวกที่สุดคือการใช้@FetchRequestหรือ@SectionedFetchRequest wrappers ในทุก ๆ มุมมองที่คุณต้องอ่านจาก CoreData

การส่งอ็อบเจกต์ที่ดึงมาระหว่าง Views จะทำให้การอัปเดตอัตโนมัติหยุดชะงัก ในกรณีที่คุณเพิ่ม แก้ไข หรือลบอ็อบเจ็กต์ (หากคุณทราบวิธีส่งผ่านวัตถุดึงข้อมูลโดยไม่ทำให้การอัปเดตเสียหาย โปรดแจ้งให้เราทราบ และฉันจะอัปเดตคู่มือนี้)

ดังนั้นคุณต้องเพิ่ม@FetchRequestในทุกมุมมองที่คุณต้องการวัตถุ CoreData และการอัปเดตอัตโนมัติ ฉันรู้ว่ามันค่อนข้างน่ารำคาญ แต่มันจะคุ้มค่า

ดังนั้นโดยที่กล่าวว่ารหัสมีดังต่อไปนี้:

@FetchRequest(entity: \Object.type,
              sortDescriptors: [NSSortDescriptor],
              predicate: NSPredicate,
              animation: .default)
var objects: [Object]

@SectionedFetchRequest(entity: \Object.type,
                         sectionIdentifier: \Object.property,
                         sortDescriptors: [NSSortDescriptor],
                         predicate: NSPredicate,
                         animation: .default)
var sections: SectionedFetchResults<YourSectionType, Object>

List(sections) { section in
  Section(section.id) {
    ForEach(section) { object in
      // Configure your view with the object
    }
  }
}

การใช้@FetchRequestหรือ@SectionedFetchRequestทุกที่ที่คุณเพิ่ม อัปเดต หรือลบออบเจ็กต์ มุมมองจะได้รับการอัปเดตโดยอัตโนมัติ

ตอนนี้ ถ้าคุณต้องการใช้ @FetchRequest กับ NSPredicate ที่มีพารามิเตอร์ที่ส่งมาจากพาเรนต์ View ฉันพบว่าตัวเลือกถัดไปใช้งานได้อย่างยอดเยี่ยม

@FetchRequest
var objects: FetchedResults<Object>

init(id: ID) {
  _objects = FetchRequest<Object>(predicate: NSPredicate(format: "id == %@", id))
}

การปรับปรุงวัตถุ

ในการอัปเดต a NSManagedObjectคุณจะต้องNSManagedObjectอัปเดต ดึงข้อมูลตามที่อธิบายไว้ก่อนหน้า และอัปเดตคุณสมบัติ แล้วบันทึกบริบท

note.text = newText
note.folder = newFolder
saveContext()

หากต้องการลบ a NSManagedObjectคุณจะต้องNSManagedObjectอัปเดต ดึงข้อมูลตามที่อธิบายไว้ก่อนหน้าแล้วลบออก

viewContext.delete(object)

บทสรุป

นั่นคือทั้งหมดที่ฉันค้นพบเกี่ยวกับ CoreData ที่ใช้กับ SwiftUI คู่มือนี้จะได้รับการปรับปรุงอย่างต่อเนื่อง

หากคุณต้องการแนะนำวิธีการทำสิ่งที่ดีกว่าโปรดแสดงความคิดเห็นแล้วเราจะอัปเดตคู่มือนี้ด้วยตัวเลือกที่ดีที่สุด

ฉันหวังว่าฉันจะช่วยคุณในการเดินทางด้วยการพัฒนา SwiftUI และ iOS

ปรบมือถ้าคุณชอบบทความนี้ ฉันซาบซึ้งมาก

พบกันใหม่ในคู่มือหน้า!

หากคุณต้องการสนับสนุนงานของฉันและดูคู่มือนี้ในการดำเนิน การลองดูBrainDump — Notes & Writing

ขอบคุณค่ะ