SwiftUI:删除行时使用数组/索引的ForEach崩溃 [英] SwiftUI: ForEach using Array/Index crashes when rows are deleted

查看:104
本文介绍了SwiftUI:删除行时使用数组/索引的ForEach崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经看过几篇关于此的文章,但到目前为止,没有一种解决方案对我有用.

I've seen several posts about this, but so far none of the solutions seem to be working for me.

我正在尝试使用ForEach创建可识别项目的数组-里面同时具有 Text() Toggle()视图.数组存储在 @ObservableObject @Published 属性中.

I'm trying to create an array of Identifiable items using ForEach -- with both a Text() and Toggle() view inside. The array is stored in a @Published property of an @ObservableObject.

我目前正在遍历索引以创建切换绑定(如

I'm currently looping through the indices to create the toggle bindings (as suggested in other posts).

一切正常,直到我尝试删除一行.

Everything appears to be working, until I try to delete a row.

(特别是最后一行-每次都会触发致命错误:索引超出范围".)

(Specifically the last row - which triggers a "Fatal error: Index out of range" every time.)

任何帮助将不胜感激!

struct Rule: Identifiable {
  let id: String
  var displayName: String
  var isEnabled: Bool
}

class UserData: ObservableObject {
  @Published var rules: [Rule] = []
}

struct RuleListView: View {
  @ObservableObject var userData: UserData

  var body: some View {
    List {
      ForEach(userData.rules.indices, id: \.self) { index in
        HStack {
          Toggle(
            isOn: self.$userData.rules[index].isEnabled
          ) { Text("Enabled") }
          Text(self.userData.rules[index].displayName)
        }
      }
      .onDelete(perform: delete)
    }
  }

  func delete(at offsets: IndexSet) {
    userData.rules.remove(atOffsets: offsets)
  }
}

推荐答案

似乎您的代码很复杂:

class UserData: ObservableObject {
  @Published var rules: [Rule] = []
}

当将新元素添加到规则数组时,您会注意到,您只需声明以下内容即可完成

Will notice when new element is added to rules array, you could have done that just by declaring:

@State var rules = [Rule]()

您可能想知道 Rule 类中的 isEnabled 何时更改.现在这还没有发生.为此, ObservableObject 必须是 Rule 类.

You probably want to know when isEnabled in Rule class changes. Right now it is not happening. For that to ObservableObject must be the Rule class.

请记住,如果将代码更改为:

Keeping that in mind, if you change your code to:

import SwiftUI

class Rule: ObservableObject, Identifiable {
  let id: String
  var displayName: String
  @Published var isEnabled: Bool

  init(id: String, displayName: String, isEnabled: Bool) {
    self.id = id
    self.displayName = displayName
    self.isEnabled = isEnabled
  }
}

struct ContentView: View {
  // for demonstration purpose, you may just declare an empty array here
  @State var rules: [Rule] = [
    Rule(id: "0", displayName: "a", isEnabled: true),
    Rule(id: "1", displayName: "b", isEnabled: true),
    Rule(id: "2", displayName: "c", isEnabled: true)
  ]

  var body: some View {
    VStack {
      List {
        ForEach(rules) { rule in
          Row(rule: rule)
        }
        .onDelete(perform: delete)
      }
    }
  }

  func delete(at offsets: IndexSet) {
    rules.remove(atOffsets: offsets)
  }
}

struct Row: View {
  @ObservedObject var rule: Rule

  var body: some View {
    HStack {
      Toggle(isOn: self.$rule.isEnabled)
      { Text("Enabled") }

      Text(rule.displayName)
        .foregroundColor(rule.isEnabled ? Color.green : Color.red)
    }
  }
}

它将注意到何时将新元素添加到rules数组,也将注意到何时 isEnabled 更改.这也解决了您的崩溃问题.

It will notice when new element is added to rules array, and also will notice when isEnabled changes. This also solves your problem with crashing.

这篇关于SwiftUI:删除行时使用数组/索引的ForEach崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆