私は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() }
}}
}
しかし、2 つの積み重ねられたリスト (以下を参照) を使用するように切り替えると、問題はなくなります。タップして目標を完了すると、それが一番下のリストに移動し、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
以下に含まれているのは、 from an extension toの私の定義ですDay
。これにより、2 つがどのように定義され、関連しているかが明らかになります。それぞれ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()
}