删除视图中的绑定对象时出现“致命错误:索引超出范围”

2024-04-19

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

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

我在下面附上了代码示例。如果您有任何问题或者我还需要添加其他内容,请告诉我!在此先感谢您的帮助!

锻炼列表(家长视图)

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.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 )
    }
}

ActiveWorkout商店

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)
        }
    }
}

Workout

import SwiftUI

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

ForEach<Range>是常量范围容器(注意下面构造函数的说明),构造后不允许修改。

extension ForEach where Data == Range<Int>, ID == Int, Content : View {

    /// Creates an instance that computes views on demand over a *constant*
    /// range.
    ///
    /// This instance only reads the initial value of `data` and so it does not
    /// need to identify views across updates.
    ///
    /// To compute views on demand over a dynamic range use
    /// `ForEach(_:id:content:)`.
    public init(_ data: Range<Int>, @ViewBuilder content: @escaping (Int) -> Content)
}

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

删除视图中的绑定对象时出现“致命错误:索引超出范围” 的相关文章

  • 在 swift 中从本地视频创建缩略图

    如何从本地视频文件快速创建缩略图 例如 如果视频文件路径位于此处 file Users Dev Library Developer CoreSimulator Devices F33222DF D8F0 448B A127 C5B03C64
  • Swift - 停止 avaudioplayer

    我正在尝试将音板构建到应用程序中 并找到了一种使用标签来控制播放声音的有效方法 不过 我现在正在尝试集成一个可以与 stop 方法上的AVAudioPlayer但是我当前的代码出现错误 EXC BAD ACCESS 这就是我现在正在使用的
  • 将浮点数截断为小数点后两位的最简单方法?

    在 Swift 中 有没有办法将浮点数截断为小数点后两位 以便您可以用它执行进一步的计算 我见过的所有线程都涉及到字符串的转换 我不知道如何在数学上使用它 我尝试使用扩展 在这个论坛上找到 认为我可以在截断后转换回浮动 但我最终回到了开始的
  • Swift 错误:无法从 AST 上下文获取模块“My_App”

    我正在使用 Swift 3 Xcode 8 1 CocoaPods 1 1 1 运行后pod update 每次我尝试使用 Xcode 的 lldb 控制台时 它都会打印错误 例如 po self输出 共享 Swift 状态My App已出
  • 如何让应用更新以吸引人的屏幕形式提供给用户? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我最近在使用 Make My Trip 应用程序 我发现每当我启动应用程序时都会出现一个非常有吸引力的应用程序更新弹出屏幕 它说要更新应用程
  • Swift Firebase - 如何在使用 queryOrdered(byChild: ).queryEqual(toValue: ) 时获取所有 k/v

    root reviews postABC postId reviewXYZ I want everything under this reviewUID buyerUID 01010 text fast shipping responseT
  • 我的结构不符合协议“Decodable”/“Encodable”

    我试图使用 Codable 来保存我正在创建的应用程序中的数据 但是当我将 Codable 放入我的结构中时 我不断收到错误 类型 ReminderGroups 不符合协议 Decodable and 类型 ReminderGroups 不
  • 解包可选值时意外发现 nil - 使用 ALAMOFIRE

    我正在尝试使用 Alamofire 获取 JSON 格式的数据 当我使用一个 URL 时 它工作正常 当我使用另一个 URL 时 我在解包可选值时收到错误 我似乎无法追踪错误来自哪里 我已采取将代码放入 ViewDidLoad 来跟踪错误
  • 如何将图像转换为 UIImage?

    如何转换 SwiftUIImage to a UIImage let image Image systemName circle fill let UIImage image as UIImage 没有直接的方法将 Image 转换为 UI
  • swift 中闭包和函数作为参数的区别

    我有将近 4 年的 Objective C 经验 并且是 swift 的新手 我试图从 Objective C 的角度理解 swift 的概念 所以如果我错了 请指导我 在目标 c 中 我们有块 可以稍后异步执行的代码块 这绝对是完全合理的
  • 具有透明背景的 Swift 模态视图控制器 [重复]

    这个问题在这里已经有答案了 我知道这个话题很受欢迎 但我在编程语言中遇到了一些问题 事实是我仍然不明白我把代码放在哪里 好吧 我就来说说整个案子 我正在尝试制作一个与正常情况稍有不同的模态 Swift 通过单击按钮 ViewControll
  • 如何快速防止标签中出现孤儿?

    我有一个可以有一两行的标签 如果它有两行 我希望第二行至少有两个 或者可能三个 单词 而不仅仅是一个 关于如何使用 swift 实现这一点有什么想法吗 提前致谢 Daniel 编辑 我删除了我愚蠢的第一个想法 这些想法并没有真正的帮助 好吧
  • SwiftUI - 从 NSObject 继承的 ObservableObject 在 iOS 13 中不会更新

    我知道 这是 无法在 iOS XX 中工作 问题之一 但我完全陷入困境 所以我有一个ObservableObject继承自的类NSObject 因为我需要听委托方法UISearchResultsUpdating class SearchBa
  • 如何像谷歌日历一样将单元格的内容滚动到表格视图中的另一个单元格中?

    我希望用户界面像谷歌日历那样进入桌面视图 它在不同的行中显示相同的日期事件 但是当您向上或向下滚动时 左侧的日期也会向上向下滚动 Can you please help me how to achieve this Please take
  • HStack 中的 SwiftUI EditButton 未激活编辑模式

    作为更大表单的一部分 我希望有一个带有列表的部分 其条目可以重新排序 在整个视图中 应该只能编辑该特定列表 而不能编辑其他内容 因此我希望将编辑按钮放在列表附近 如果我只是将 EditButton 设置为节标题 则可以对列表项重新排序 但无
  • iOS 11 浮动 TableView 标题

    有一个应用程序包含多个部分 展开 时每个部分有几行 折叠 时没有 每个部分都有一个部分标题 使用以下子类重用它们UITableViewHeaderFooterView等等 到目前为止一切顺利 然后在 iOS 11 中 我使用了可视化调试器
  • 如何从 Firebase 同步检索数据?

    我有两个集合 即用户和问题 根据使用 userId 登录的用户 我检索currQuestion价值来自users收藏 基于currQuestion值 我需要检索question来自 Firebase 的文档Questions收藏 我使用下面
  • 如何在 Swift 中创建 UIAlertView?

    我一直在努力在 Swift 中创建 UIAlertView 但由于某种原因我无法得到正确的语句 因为我收到此错误 找不到接受提供的 init 重载 论点 我是这样写的 let button2Alert UIAlertView UIAlert
  • 进入后台时 Alamofire 请求卡住?

    我正在使用 Alamofire 调用 Web 服务 该服务需要相当长的时间才能加载 如果应用程序进入后台 当我返回应用程序时 我会被加载程序卡住 我想这是因为调用永远不会向我的完成处理程序返回任何内容 我该如何解决这个问题 您可以使用后台抓
  • iOS WKWebView 处理文件下载

    我面临以下问题 在 Web 界面中 文件下载是通过锚标记触发的 如下所示 a href bla blabla a 虽然 Safari 浏览器可以处理此请求并打开一个对话框来处理文件 但 WKWebView 将此视为普通链接并且不对其执行任何

随机推荐

  • Angular2 可观察定时器条件

    我有一个计时器 initiateTimer if this timerSub this destroyTimer let timer TimerObservable create 0 1000 this timerSub timer sub
  • 如何解决 WPF 中的“绑定表达式路径错误”?

    我将模型对象的可观察集合绑定到数据网格 但是当我将绑定设置到集合时 我收到了指向人员的路径错误 在调试此问题时 我检查了 CustomerModel 中的公共属性在 DataGrid 绑定中是否正确命名 而且返回到模型的集合不为空 我还检查
  • 为什么使用window.onload

    我尝试自己找到这个问题的答案 但只找到了有关如何使用 onload 事件的说明 我似乎没有抓住要点 我被告知 如果我希望在页面加载时发生某些事情 我应该像这样使用 window onload 但现在我自己思考 我想知道这样做的意义是什么 因
  • 将 forMine 设置为 false 进行搜索时,youtube v3 api 错误

    我正在编写一些函数Youtube API version 3 我在用python但在谷歌提供的测试控制台中确认了我的错误 我正在提出所有授权请求 只是没有在下面粘贴我的密钥 Python 客户端库自动添加forMine参数给我的Search
  • 如何在不暂存的情况下 git 添加新文件?

    为了有效地 并按预期 使用 git 我进行了小的原子提交 而我确实有更长的会话 我所做的不仅仅是一件事 因此 我大量使用git add p 不过 这不适用于全新的文件 因为我以后往往会忘记它们 我想做的是告诉git那里is一个新文件 我希望
  • 我在哪里可以学习编写词法分析器的基础知识?

    我想学习如何编写词法分析器 我的大学课程有一项作业 我们必须编写一个解析器 以及与之配套的词法分析器 但这是给我们的 没有任何指导或反馈 超出了标准 所以我并没有真正从中学到很多东西 搜索这个主题后 我只能找到相当高级的文章 这些文章重点关
  • 如何通过 UNC 加速 Powershell Get-Childitem

    DIR or GCI在 Powershell 中很慢 但在 CMD 中很快 有什么办法可以加快这个速度吗 在 CMD exe 中 经过亚秒级延迟后 其响应速度与 CMD 窗口可以跟上的速度一样快 dir remote server doma
  • OpenJPA 的 Maven 原型

    问候 我刚刚开始探索 Maven 我使用 m2eclipse 就像在 Eclipse 中使用 Maven 一样 我发现有一个基于休眠的原型 组 ID com rfc maven archetypes 和 工件 ID jpa maven ar
  • 使用矩形在图像上创建搜索区域

    我有一个显示图像的图像查看器 我想使用鼠标在图像上绘制一个矩形 并获取矩形的 x 和 y 坐标 X1 X2 Y1 和 Y2 我将使用这些坐标创建一个搜索区域 并在数组中查找最大值和最小值 该数组的两个轴上的像素数与图像的像素数完全相同 有人
  • 如何在C++中初始化结构体数组?

    我有以下内容struct在我的 C 代码中 我使用的是 Visual Studio 2010 struct mydata string scientist double value 我想做的是能够以快速的方式初始化它们 类似于 C99 中的
  • PHP- HTML 解析 :: 如何使用简单的 html dom 解析器获取网页的字符集值?

    PHP 如何简单地获取网页的字符集值html dom 解析器 http simplehtmldom sourceforge net utf 8 windows 255 等 备注 必须使用 html dom 解析器来完成http simple
  • Symfony2 createQuery 按字段排序

    你好 我在 phpmyadmin 中写了这个查询 它可以工作 gr8 SELECT u FROM users AS u WHERE u id 14469 OR u id 685 ORDER BY u id field u id 14469
  • FFMPEG - 连续的非单调 DTS

    我有几个需要连接的文件 有时文件工作和连接似乎没有问题 然后在其他文件上 文件不会连接 我得到 非单调 DTS 我一直在谷歌上搜索我应该对这些文件进行哪些处理 以便它们正确连接 但我仍然没有找到 有没有办法让所有文件的 DTS 完全相同 我
  • 是否可以使用不同的占位符掩码输入?

    由于我的表单没有标签 我希望能够在 Angular 和 Angular UI Utils Mask 中使用不同的占位符 div div
  • AutoCAD 如何计算仅由拟合点定义的样条曲线的终点切线?

    AutoCAD 允许将 SPLINE 实体存储在仅由以下定义的 DXF 文件中 拟合点 问题是 这样的样条定义有无限 数值正确的解决方案 Autodesk 不提供必要的 从给定的拟合点计算所需参数的信息 tl dr 缺少的信息是估计的起点和
  • 图像轮廓轴

    对于放射线扫描 我已经能够获取轮廓 我有兴趣找到中心轴 我怎样才能用Python做到这一点 这是我的轮廓代码 import cv2 img cv2 imread A png imgray cv2 cvtColor img cv2 COLOR
  • 字符串终止符'\0'如何与整数常量0具有相同的值?

    我有以下代码 include
  • iOS 中离线网站的最佳实践

    我正在构建一个需要下载大量 html5 内容的应用程序 本质上 它的工作原理与您在 iPad 上看到的杂志应用程序类似 只是它不使用图像 而是使用 UIWebViews 和 HTML 我的问题是存储它的最佳方法是什么 我正在考虑要么将下载的
  • 当“卸载...”按钮被禁用时卸载 Eclipse 插件

    有时 由于某种原因 帮助 gt 关于 Eclipse gt 安装详细信息 中的 卸载 按钮被禁用 例如 安装 Aptana 插件后 这会强制在 Eclipse Galileo 中使用较旧的安装程序 如何在禁用 卸载 的情况下删除这些插件 尝
  • 删除视图中的绑定对象时出现“致命错误:索引超出范围”

    在修改子视图依赖于绑定对象的数组时 我在避免索引超出范围错误时遇到了一些麻烦 我有一个名为 WorkoutList 的父视图 WorkoutList 有一个 ActiveWorkoutStore 的 EnvironmentObject Ac