核心数据错误地更新多个对象

时间:2020-01-26 01:38:04

标签: swift swiftui nsmanagedobject

对于上下文,知道我对Swift,SwiftUI,Core Data和面向事件的对象编程完全陌生。我正在编写一个iOS应用程序,作为尝试学习这些框架的一种方式。

我正在编写一个基本的健身房跟踪应用程序。我的核心数据模型包含3个实体: 运动,具有exerciseName和executionNotes的属性,以及与MuscleGroup和Type的1-1关系。

类型,具有属性typeName,并且与“锻炼”具有1-Many关系

MuscleGroup,其属性为muscleGroupName,并且与“运动”具有1-Many关系

我正在使用NavigationView从所有练习的列表开始,并使用NavigationLink访问详细视图,该视图是用于编辑现有列表项的表单。

在详细信息视图中,我具有用于exerciseName和exerciseNotes的文本字段,以及用于muscleGroupName的选择器,该选择器由可用选项的恒定数组填充,并且默认选择为从列表中选择的任何对象的值。 / p>

无论如何,当我编辑exerciseName或exerciseNotes时,更改就可以了。如果我编辑muscleGroup关系(exercise.exerciseToMuscleGroup.muscleGroupName),所做的更改确实会保存到核心数据,但是似乎正在更新Exercise实体中每个对象的关系,该对象的exerciseToMuscleGroup.muscleGroupName值相同。例如,如果我有3个练习: -腿部推举(肌肉群名称=腿部) -Bicep Curl(肌肉组名称=手臂) -胸部按压(肌肉组名称=胸部)

这样,如果我进入编辑Bicep Curl,然后将“肌肉组名称”更改为“腿”,那就很好-可以。如果我返回到Bicep Curl,并将“肌肉组名称”更改回Arms,则还将“腿部按压肌肉组名称”设置为Arms,因此现在Leg Press和Bicep Curl都为exercise.exerciseToMuscleGroup.muscleGroupName设置了“ Arms”。如果我将“胸部按压”更改为“肌肉群=手臂”,它仍然可以工作,但是现在,如果我在3个练习中的任何一个上更改了“肌肉群”,它们都将更新为新的肌肉群。

我将对任何有关如何正确使用此方法的指导表示赞赏,以便仅更新详细视图中的Exercise实例。

//
//  StrengthExerciseDetail.swift


import SwiftUI
import CoreData

struct StrengthExerciseDetail: View {
    @Environment(\.managedObjectContext) var moc
    let exercise: Exercise

    @State private var notes: String
    @State private var name: String
    @State private var muscleGroupName: String
    @State private var muscleGroupIndex: Int = 0
    let muscleGroupNames: [String] = ["Abdominals", "Arms", "Back", "Chest", "Legs", "Shoulders"]

    init(exercise: Exercise) {
        self.exercise = exercise
        // Define the initial form field values
        _notes = .init(initialValue: exercise.wrappedExerciseNotes)
        _name = .init(initialValue: exercise.wrappedExerciseName)
        _muscleGroupName = .init(initialValue: exercise.exerciseToMuscleGroup!.wrappedMuscleGroupName)

        // Set the Muscle Group picker selection
        var currentIndex: Int = 0
        for muscle in muscleGroupNames {
            if muscle == muscleGroupName {
                _muscleGroupIndex = .init(initialValue: currentIndex)
            } else {
                currentIndex += 1
            }
        }
        currentIndex = 0
    }

    func updateExercise(_ exercise: Exercise) {
        print("running update exercise")

        do {
            print("running loop")
            let newMuscleGroupName = muscleGroupNames[muscleGroupIndex]

            exercise.setValue(name, forKey: "exerciseName")
            exercise.setValue(notes, forKey: "exerciseNotes")
            exercise.setValue(newMuscleGroupName, forKeyPath: "exerciseToMuscleGroup.muscleGroupName")
            try moc.save()
            moc.refreshAllObjects()


        } catch {
            print(error)
        }
        moc.reset()
    }

    var body: some View {
        Form {
            Section(header: Text("Exercise Name")) {
                    TextField("Name", text: $name)
            }
            Section(header: Text("Muscle Group")) {
                Picker(selection: $muscleGroupIndex, label: Text("")) {
                    ForEach(0 ..< muscleGroupNames.count) {
                        Text(self.muscleGroupNames[$0])
                    }
                }
            }
            Section(header: Text("Notes")) {
                TextField("Notes", text: $notes)
                    .frame(height: 300.0)
            }
            Button("Save Changes") {
                self.updateExercise(self.exercise)
            }
        }
    }
}

struct StrengthExerciseDetail_Previews: PreviewProvider {
    static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)

    static var previews: some View {
        let exercise = Exercise(context: moc)
        exercise.exerciseName = "Booty Bounce"
        exercise.exerciseNotes = "This is a great strength builder"
        exercise.exerciseToMuscleGroup = MuscleGroup(context: moc)
        exercise.exerciseToMuscleGroup?.muscleGroupName = "Legs"
        exercise.exerciseToType = Type(context: moc)
        exercise.exerciseToType?.typeName = "Strength"

        return NavigationView {
            StrengthExerciseDetail(exercise: exercise)
        }
    }
}

0 个答案:

没有答案