0

我在画布中预览我的 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)

    }
}

我已经将子视图从@ObservedObjectwith 类型换成GoalViewsFetchedResults<GoalViews>.Element.

当我在不同级别交换和更改 FetchedResults、ObservedObjects 和 State 时,该应用程序继续按预期运行。

从父级(获取数据)到子级(需要访问更新/删除数据)的正确数据流是什么?如果使用预览持久性控制器,这些在预览中是如何概述的?

4

0 回答 0