首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >删除绑定对象时出现的“错误:超出范围的索引”

删除绑定对象时出现的“错误:超出范围的索引”
EN

Stack Overflow用户
提问于 2019-11-21 21:34:02
回答 1查看 1.6K关注 0票数 3

当修改子视图依赖于绑定对象的数组时,我在避免索引超出范围错误时遇到了一些困难。

我有一个名为WorkoutList的父视图。WorkoutList有一个EnvironmentObject of ActiveWorkoutStore。ActiveWorkoutStore是一个ObservableObject,它有一个由Workout对象组成的数组。我有一个从ActiveWorkoutStore检索的活动锻炼的列表。我使用一个ForEach循环来处理这些活动锻炼的索引,并将一个对象绑定到一个名为EditWorkout的子视图,作为NavigationLink的目标。EditWorkout有一个按钮来完成一项锻炼,它从ActiveWorkoutStore的锻炼数组中删除它,并将其添加到WorkoutHistoryStore中。当我从ActiveWorkoutStore的activeWorkouts数组中删除这个对象时,会遇到麻烦,这会立即导致索引超出范围错误。我怀疑这是因为active视图依赖于我刚刚删除的绑定对象。我尝试过这方面的几个组合,包括将一个锻炼传递给EditWorkout,然后使用它的id在ActiveWorkoutStore中引用一个锻炼来执行我的操作,但是遇到了类似的麻烦。我在网上看到了很多例子,它们遵循利用ForEach来迭代索引的模式,并且我已经尽可能地反映了这一点,但我怀疑我可能忽略了这种方法的一些细微差别。

我在下面附上了代码样本。如果你有什么问题,或者还有什么我应该包括的,请告诉我!提前感谢您的帮助!

WorkoutList (父视图)

代码语言:javascript
复制
import SwiftUI

struct WorkoutList: View {
    @EnvironmentObject var activeWorkoutsStore: ActiveWorkoutStore
    @State private var addExercise = false
    @State private var workoutInProgress = false

    var newWorkoutButton: some View {
        Button(action: {
            self.activeWorkoutsStore.newActiveWorkout()
        }) {
            Text("New Workout")
            Image(systemName: "plus.circle")
        }
    }

    var body: some View {
        NavigationView {
            Group {
                if activeWorkoutsStore.activeWorkouts.isEmpty {
                    Text("No active workouts")
                } else {
                    List {
                        ForEach(activeWorkoutsStore.activeWorkouts.indices.reversed(), id: \.self) { activeWorkoutIndex in
                            NavigationLink(destination: EditWorkout(activeWorkout: self.$activeWorkoutsStore.activeWorkouts[activeWorkoutIndex])) {
                                Text(self.activeWorkoutsStore.activeWorkouts[activeWorkoutIndex].id.uuidString)
                            }
                        }
                    }
                }
            }
            .navigationBarTitle(Text("Active Workouts"))
            .navigationBarItems(trailing: newWorkoutButton)
        }
    }
}

EditWorkout (儿童视图)

代码语言:javascript
复制
//
//  EditWorkout.swift
//  workout-planner
//
//  Created by Dominic Minischetti III on 11/2/19.
//  Copyright © 2019 Dominic Minischetti. All rights reserved.
//

import SwiftUI

struct EditWorkout: View {
    @EnvironmentObject var workoutHistoryStore: WorkoutHistoryStore
    @EnvironmentObject var activeWorkoutStore: ActiveWorkoutStore
    @EnvironmentObject var exerciseStore: ExerciseStore
    @Environment(\.presentationMode) var presentationMode
    @State private var addExercise = false
    @Binding var activeWorkout: Workout
    
    var currentDayOfWeek: String {
        let weekdayIndex = Calendar.current.component(.weekday, from: Date())
        return Calendar.current.weekdaySymbols[weekdayIndex - 1]
    }

    var chooseExercisesButton: some View {
        Button (action: {
            self.addExercise = true
        }) {
            HStack {
                Image(systemName: "plus.square")
                Text("Choose Exercises")
            }
        }
        .sheet(isPresented: self.$addExercise) {
            AddWorkoutExercise(exercises: self.$activeWorkout.exercises)
                .environmentObject(self.exerciseStore)

        }
    }
    
    var saveButton: some View {
        Button(action: {
            self.workoutHistoryStore.addWorkout(workout: self.$activeWorkout.wrappedValue)
            self.activeWorkoutStore.removeActiveWorkout(workout: self.$activeWorkout.wrappedValue)
            self.presentationMode.wrappedValue.dismiss()
        }) {
            Text("Finish Workout")
        }
        .disabled(self.$activeWorkout.wrappedValue.exercises.isEmpty)
    }

    var body: some View {
        Form {
            Section(footer: Text("Choose which exercises are part of this workout")) {
                chooseExercisesButton
            }
            Section(header: Text("Exercises")) {
                if $activeWorkout.wrappedValue.exercises.isEmpty {
                    Text("No exercises")
                } else {
                    ForEach(activeWorkout.exercises.indices, id: \.self) { exerciseIndex in
                        NavigationLink(destination: EditWorkoutExercise(exercise: self.$activeWorkout.exercises[exerciseIndex])) {
                            VStack(alignment: .leading) {
                                Text(self.activeWorkout.exercises[exerciseIndex].name)
                                Text("\(self.activeWorkout.exercises[exerciseIndex].sets.count) Set\(self.activeWorkout.exercises[exerciseIndex].sets.count == 1 ? "" : "s")")
                                    .font(.footnote)
                                    .opacity(0.5)
                            }
                        }
                    }
                    saveButton
                }
            }
        }
        .navigationBarTitle(Text("Edit Workout"), displayMode: .inline )
    }
}

ActiveWorkoutStore

代码语言:javascript
复制
import Foundation
import Combine

class ActiveWorkoutStore: ObservableObject {
    @Published var activeWorkouts: [Workout] = []
    
    func newActiveWorkout() {
        activeWorkouts.append(Workout())
    }
    
    func saveActiveWorkout(workout: Workout) {
        let workoutIndex = activeWorkouts.firstIndex(where: { $0.id == workout.id })!
        
        activeWorkouts[workoutIndex] = workout
    }
    
    func removeActiveWorkout(workout: Workout) {
        if let workoutIndex = activeWorkouts.firstIndex(where: { $0.id == workout.id }) {
            activeWorkouts.remove(at: workoutIndex)
        }
    }
}

锻炼身体

代码语言:javascript
复制
import SwiftUI

struct Workout: Hashable, Codable, Identifiable {
    var id = UUID()
    var date = Date()
    var exercises: [WorkoutExercise] = []
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-11-23 12:56:59

ForEach<Range>是常量容器(请注意下面的构造函数描述),它不允许在构造后修改它。

ForEach == Range,ID == Int,Content : View {/创建一个实例,根据需要在*常量*//范围内计算视图。/此实例只读取data的初始值,因此它不需要跨更新标识视图。/若要计算动态范围内的按需视图,请使用/ ForEach(\_:id:content:)。公共init(_ data: Range,@ViewBuilder内容:@转义(Int) ->内容)}

如果要修改容器,则必须使用ForEach(activeWorkout.exercises)

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58984109

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档