Несколько ForEach в одном списке против нескольких списков с одним ForEach
Я новичок в 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
s / 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()
}
1 ответ
Код для меня не поддается тестированию, поэтому просто идея - попробуйте следующее
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 !!
}
}}
}