0

私は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) は両方ともNSManagedObjects / 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()
}
4

1 に答える 1