Ios 当用户使用SwiftUI进入新视图时,如何刷新核心数据阵列?

Ios 当用户使用SwiftUI进入新视图时,如何刷新核心数据阵列?,ios,swift,core-data,swiftui,Ios,Swift,Core Data,Swiftui,我有三种观点。内容视图、培训视图和培训列表视图。我想列出核心数据中的练习,但也希望在不改变数据的情况下进行一些更改 在ContentView中;我正在尝试使用CoreData获取数据 struct ContentView: View { // MARK: - PROPERTY @FetchRequest( sortDescriptors: [NSSortDescriptor(keyPath: \Training.timestamp, ascending:

我有三种观点。内容视图、培训视图和培训列表视图。我想列出核心数据中的练习,但也希望在不改变数据的情况下进行一些更改

在ContentView中;我正在尝试使用CoreData获取数据

struct ContentView: View {
    // MARK: - PROPERTY
    
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Training.timestamp, ascending: false)],
        animation: .default)
    private var trainings: FetchedResults<Training>
    
    @State private var showingAddProgram: Bool = false
    
    // FETCHING DATA
    
    
    // MARK: - FUNCTION
    
    // MARK: - BODY
    
    var body: some View {
        NavigationView {
            Group {
                VStack {
                    HStack {
                        Text("Your Programs")
                        Spacer()
                        Button(action: {
                            self.showingAddProgram.toggle()
                        }) {
                            Image(systemName: "plus")
                        }
                        .sheet(isPresented: $showingAddProgram) {
                            AddProgramView()
                        }
                        
                    } //: HSTACK
                    .padding()
                    List {
                        ForEach(trainings) { training in
                            TrainingListView(training: training)
                        }
                    } //: LIST
                    Spacer()
                } //: VSTACK
            } //: GROUP
            .navigationTitle("Good Morning")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {
                        print("test")
                    }) {
                        Image(systemName: "key")
                    }
                }
            } //: TOOLBAR
            .onAppear() {
                
            }
        } //: NAVIGATION
    }
    
    private func showId(training: Training) {
        guard let id = training.id else { return }
        print(id)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
    }
}
另外,我正在添加视频:


我想做的是,当用户点击任何训练练习时,列表都应该刷新。应该是x5,就像一开始一样。

我很难理解你的问题,但我想我明白了

我的理解是:

  • 您希望将代表计数存储在核心数据中。(在“训练>练习”下)
  • 您希望在用户完成练习时逐个倒数重复次数
  • 但您不想更改存储在核心数据中的原始rep计数
  • 我没有运行你的代码,因为我不想重新创建所有的模型和核心数据文件。我想我已经发现了问题所在。在这里,我将解释如何解决这个问题:

    核心数据模型是类(引用类型)。当您传递类(就像在代码中那样)并更改它们的属性时,您就更改了原始数据。在你的情况下,你不想这样

    (顺便说一句,作为引用类型是类非常有用和强大的属性。结构和枚举是值类型,即它们在传递时被复制。原始数据不变。)

    您有几种解决问题的方法:

  • 只需从
    练习
    生成一个不同的
    结构
    (类似
    练习显示
    ),然后将
    练习显示
    传递到
    培训视图

  • 您可以将
    扩展名
    写入
    练习
    ,并在将模型传递到
    培训视图
    之前“复制”模型。为此,您需要实现
    NSCopying
    协议

  • 扩展练习:NSCopying{
    func副本(带区域:NSZone?=nil)->任何{
    返回练习(……)
    }
    }
    
    但在执行此操作之前,我想您需要将
    .xcdatamodeld
    文件中的Codegen更改为Manual/None。当您想要手动创建属性时,这是必需的。我不确定如何为CoreDate模型实现
    NSCopying
    ,但它确实是可行的


    第一种方法比较简单,但有点难看。第二种更通用、更优雅,但也更先进。只要先尝试第一种方法,一旦你感到自信,就转向第二种方法


    更新: 下面简要介绍如何实施第一种方法:

    struct ExerciseDisplay:可识别、可平衡{
    公共let id=UUID()
    公共let名称:String
    公共变量代表:Int
    公众休息时间:Int
    }
    结构训练视图:视图{
    //其他属性和状态等。
    让培训:培训
    @状态变量练习:[ExerciseDisplay]=[]
    初始(培训:培训){
    自我训练
    }
    var body:一些观点{
    VStack{
    //观点
    }
    .onAppear(){
    让存储:[练习]=训练.练习?.toArray()??[]
    self.exerces=stored.map{ExerciseDisplay(名称:$0.name??”,rep:Int($0.rep),rest:Int($0.rest))}
    }
    }
    }
    
    这里的问题到底是什么?你能澄清你的问题吗?@JoakimDanielson我添加了额外的资源。@Hüseyinİyibaş你能不能因为其他利益而将其标记为接受?@emrcftci是的,这是正确的,我接受了。
    import SwiftUI
    
    struct TrainingView: View {
        @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
        
        @State var training: Training
        @State var exercises: [Exercise]
        @State var tempExercises: [Exercise] = [Exercise]()
        @State var timeRemaining = 0
        @State var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
        @State var isTimerOn = false
    
        var body: some View {
            VStack {
                HStack {
                    Text("\(training.name ?? "")")
                    Spacer()
                    Button(action: {
                        presentationMode.wrappedValue.dismiss()
                    }) {
                        Text("Finish")
                    }
                }
                .padding()
                
                ZStack {
                    Circle()
                        .fill(Color.blue)
                        .frame(width: 250, height: 250)
                    Circle()
                        .fill(Color.white)
                        .frame(width: 240, height: 240)
                    Text("\(timeRemaining)s")
                        .font(.system(size: 100))
                        .fontWeight(.ultraLight)
                        .onReceive(timer) { _ in
                            if isTimerOn {
                                if timeRemaining > 0 {
                                    timeRemaining -= 1
                                } else {
                                    isTimerOn.toggle()
                                    stopTimer()
                                    removeExercise()
                                }
                            }
                        }
                }
                Button(action: {
                    startResting()
                }) {
                    if isTimerOn {
                        Text("CANCEL")
                    } else {
                        Text("GIVE A BREAK")
                    }
                }
                Spacer()
                ExerciseListView(exercises: $tempExercises)
            }
            .navigationBarHidden(true)
            .onAppear() {
                updateBigTimer()
            }
        }
        
        private func startResting() {
            tempExercises = exercises
            
            if let currentExercise: Exercise = tempExercises.first {
                timeRemaining = Int(currentExercise.rest)
                startTimer()
                isTimerOn.toggle()
            }
        }
        
        private func removeExercise() {
            if let currentExercise: Exercise = tempExercises.first {
                if Int(currentExercise.rep) == 1 {
                    let index = tempExercises.firstIndex(of: currentExercise) ?? 0
                    tempExercises.remove(at: index)
                } else if Int(currentExercise.rep) > 1 {
                    currentExercise.rep -= 1
                    let index = tempExercises.firstIndex(of: currentExercise) ?? 0
                    tempExercises.remove(at: index)
                    tempExercises.insert(currentExercise, at: index)
                }
                updateBigTimer()
            }
        }
        
        private func updateBigTimer() {
            timeRemaining = Int(tempExercises.first?.rest ?? 0)
        }
        
        private func stopTimer() {
            timer.upstream.connect().cancel()
        }
        
        private func startTimer() {
            timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
        }
    }
    
    struct TrainingView_Previews: PreviewProvider {
        static var previews: some View {
            TrainingView(training: Training(), exercises: [Exercise]())
        }
    }
    
    struct TrainingListView: View {
        
        @ObservedObject var training: Training
        @Environment(\.managedObjectContext) private var managedObjectContext
        
        var body: some View {
            NavigationLink(destination: TrainingView(training: training, exercises: training.exercises?.toArray() ?? [Exercise]())) {
                HStack {
                    Text("\(training.name ?? "")")
                    Text("\(training.exercises?.count ?? 0) exercises")
                }
            }
        }
    }