对于上下文,知道我对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)
}
}
}