我是iOS和SwiftUI的新手,并且正在制作一个“目标”应用。我要引用的代码是一个简单的列表,在标记为已完成的目标之上列出了未完成的目标。尝试将多个ForEach
放在同一List
中时遇到了一个有趣的问题。
当我使用下面的代码时,点击一个不完整的目标(从第一个foreach)会将目标移至边界以下,但是GoalView()
构造函数不会重新运行,因此该目标仍然显示为不完整,而且,它仍然保留了原始的闭包(goal.markComplete()
),这将导致崩溃。值得注意的是,today
是@ObservedObject
,并且通过调用markComplete()
和markIncomplete()
List {
ForEach(today.incompleteGoals, id: \.id) { goal in
GoalView(goal: goal, isCompleted: false)
.onTapGesture { goal.markComplete() }
}}
Text("---Boundary---")
ForEach(today.completedGoals, id: \.id) { goal in
GoalView(goal: goal, isCompleted: true)
.onTapGesture { goal.markIncomplete() }
}}
}
但是,当我切换为使用两个堆叠的列表(见下文)时,问题就消失了。轻击以完成目标,将其移至底部列表,然后GoalView()
构造函数运行,更改目标的外观和行为。
VStack {
List {
ForEach(today.incompleteGoals, id: \.id) { goal in
GoalView(goal: goal, isCompleted: false)
.onTapGesture { goal.markComplete() }
}}}
Text("---Boundary---")
List {
ForEach(today.completedGoals, id: \.id) { goal in
GoalView(goal: goal, isCompleted: true)
.onTapGesture { goal.markIncomplete() }
}}}
}
最根本的区别是什么会导致此底部实现重新运行GoalView()
闭包中的ForEach
而顶部隐含。不是吗我对为什么两个实现都将完成的目标都移到边界以下感到特别困惑,尽管最顶层似乎并没有执行第二个ForEach
附带的闭包。任何解释/提示将不胜感激!
编辑:today
(类型Day
)和goal
(类型Goal
)都是NSManagedObject
/ CoreData实体。以下包括completedGoals
从扩展名Day
的我的定义,这应阐明两者的定义和相关方式。每个Day
都具有称为completedGoals_
和incompleteGoals_
的关系,它们是与当天相关联的无序目标。
var completedGoals: Array<Goal> {
get {
let result = (completedGoals_ as? Set<Goal>) ?? []
return Array(result).sorted(by: ...)
}
set { completedGoals_ = Set(newValue) as NSSet }
}
这是markComplete()
从Goal
的扩展的粗略实现(daysThatDidntComplete_
是与completedGoals_
的逆关系,不完全相同):
func markComplete(on day: Day, context: NSManagedObjectContext) {
// ...check & crash if self (goal) wasn't already incomplete on day
removeFromDaysThatDidntComplete_(day) // provided by CoreData
addToDaysThatCompleted_(day) // provided by CoreData
try? context.save()
}
答案 0 :(得分:0)
代码对我来说不是可测试的,所以只是一个想法-尝试以下操作
List {
ForEach(today.incompleteGoals, id: \.id) { goal in
GoalView(goal: goal, isCompleted: false)
.onTapGesture {
goal.markComplete()
self.today.objectWillChange.send() // << here !!
}
}}
Text("---Boundary---")
ForEach(today.completedGoals, id: \.id) { goal in
GoalView(goal: goal, isCompleted: true)
.onTapGesture {
goal.markIncomplete()
self.today.objectWillChange.send() // << here !!
}
}}
}