我在画布中预览我的 SwiftUI CoreData 时遇到问题。该应用程序在模拟器和设备上按预期工作,但预览使任何使用 FetchedResult 或 ObservedObject 的预览视图崩溃(我可能使用错误?)。
我的持久性是这样设置的,使用带有提供的预览数据的预览控制器:
import CoreData
import CloudKit
struct PersistenceController {
//MARK: - 1. PERSISTENCE CONTROLLER
static let shared = PersistenceController()
//MARK: - 2. PERSISTENT CONTAINER
let container: NSPersistentContainer
//MARK: - 3. INIT (load the persistent store)
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "Training")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
}
//MARK: - 4. PREVIEW
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
let newGoalView = GoalViews(context: viewContext)
newGoalView.startDate = K.init().EndOfWeek(weeksSinceAnchorDate: 1)
newGoalView.endDate = K.init().EndOfWeek(weeksSinceAnchorDate: 2)
newGoalView.id = UUID()
newGoalView.totalDistanceUnit = "meters"
newGoalView.totalDistanceDoubleValue = 30000
newGoalView.workoutActivityType = Int16(32)
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo), The database failed to load.")
}
return result
}()
}
我在这里在父视图中预览它时遇到问题:
//
// GoalsView.swift
// Training
//
// Created by Liam Day on 03/05/2021.
//
import SwiftUI
import HealthKit
struct GoalsView: View {
//MARK: - PROPERTIES
@State var showNewGoalView: Bool = false
//MARK: - FETCHING DATA
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \GoalViews.endDate, ascending: true)],
animation: .default) var goalViews: FetchedResults<GoalViews>
func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { goalViews[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
//MARK: - BODY
var body: some View {
NavigationView {
List {
ForEach(goalViews) { goalView in
GoalViewListItemView(goalView: goalView)
}
.onDelete(perform: deleteItems)
}
.listStyle(PlainListStyle())
.navigationBarTitle(Text("Goals"), displayMode: .inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
self.showNewGoalView = true
}, label: {
Text("Add Goal")
})
}
ToolbarItem(placement: .navigationBarLeading) {
EditButton()
}
}
.sheet(isPresented: $showNewGoalView, content: {
CreateGoalView(isShowing: $showNewGoalView)
})
}
}
}
struct GoalsView_Previews: PreviewProvider {
static var previews: some View {
return GoalsView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
而在单个子视图中,GoalViewListItemView:
//
// GoalViewListItemView.swift
// Training
//
// Created by Liam Day on 30/05/2021.
//
import SwiftUI
import HealthKit
import CoreData
struct GoalViewListItemView: View {
var goalView: FetchedResults<GoalViews>.Element // changed from observed object
@State var progressValue: Double = 0
@AppStorage("distanceUnitSystemMetric") var distanceUnitSystemMetric: Bool = true
func calcGoalTotal() {
...
}
var body: some View {
NavigationLink(destination: GoalViewDetailView(goalView: goalView, progressValue: $progressValue)) {
VStack(alignment: .leading) {
Text(HKWorkoutActivityType.init(rawValue: UInt(goalView.workoutActivityType))!.commonName)
.font(.title)
Text(K.goalUnit.init(rawValue: (goalView.goalUnit ?? String("totalDistanceDoubleValue")))?.name ?? "Unkown")
Text("Start: \(Bundle.main.getDynamicDayName(date: goalView.startDate ?? Date()))")
Text("Finish: \(Bundle.main.getDynamicDayName(date: goalView.endDate ?? Date()))")
if goalView.goalUnit == K.goalUnit.totalDistanceDoubleValue.rawValue {
Text("Goal of \(Bundle.main.getDistance(totalDistanceDoubleValue: goalView.totalDistanceDoubleValue, totalDistanceUnit: HKUnit.meter().unitString, returnUnit: distanceUnitSystemMetric ? K.init().kilometer : HKUnit.mile().unitString, significantDigits: 3))")
ProgressView(
"\(Bundle.main.getDistance(totalDistanceDoubleValue: progressValue, totalDistanceUnit: HKUnit.meter().unitString, returnUnit: distanceUnitSystemMetric ? K.init().kilometer : HKUnit.mile().unitString, significantDigits: 3))",
value: (progressValue / goalView.totalDistanceDoubleValue),
total: 1
)
} else if goalView.goalUnit == K.goalUnit.totalEnergyBurnedDoubleValue.rawValue {
Text("Goal of \(String(format: "%.0f", goalView.totalEnergyBurnedDoubleValue)) KCal")
ProgressView(
"\(String(format: "%.0f", progressValue)) KCal",
value: (progressValue / goalView.totalEnergyBurnedDoubleValue),
total: 1
)
} else if goalView.goalUnit == K.goalUnit.duration.rawValue {
Text("Goal of \(Bundle.main.getHoursMinutesSeconds(timeInSeconds: goalView.duration))")
ProgressView(
"\(Bundle.main.getHoursMinutesSeconds(timeInSeconds: progressValue))",
value: (progressValue / goalView.duration),
total: 1
)
} else {
EmptyView()
}
}
}
.onAppear(perform: {
calcGoalTotal()
})
}
}
struct GoalViewListItemView_Previews: PreviewProvider {
static var previews: some View {
let viewContext = PersistenceController.preview.container.viewContext
let newGoalView = GoalViews(context: viewContext)
return GoalViewListItemView(goalView: newGoalView)
}
}
我已经将子视图从@ObservedObject
with 类型换成GoalViews
了FetchedResults<GoalViews>.Element
.
当我在不同级别交换和更改 FetchedResults、ObservedObjects 和 State 时,该应用程序继续按预期运行。
从父级(获取数据)到子级(需要访问更新/删除数据)的正确数据流是什么?如果使用预览持久性控制器,这些在预览中是如何概述的?