从 For Each 循环生成的 child 视图中删除项目会导致致命错误

Removing items from a child view generated by For Each loop causes Fatal Error

我希望你度过了一个比我更愉快的夜晚!

因此,正如我在标题中提到的,每当我尝试使用绑定从原始列表中删除一个项目时,我的 for each 循环就会崩溃。我做了一些研究,问题是每个生成一个带有 id 的视图,但是当您删除 child 视图中的项目时,它找不到内容并崩溃。 Returns 'Thread 1: Fatal error: Index out of range'。我可以通过声明 @State var 而不是 @Binding 来解决这个问题,这确实有效!但是,我的 child 视图中有多个删除按钮,如果我不使用绑定声明,所做的更改不会反映在主视图中。我不想放弃删除按钮和按钮。有没有办法将它们全部保留在我的 child 视图中?

主视图声明;

    struct ContentView: View {
    @ObservedObject var superReminders = SuperReminders()
    @State var superReminder = SuperReminder()}

我的列表查看;

           List{
                    ForEach(superReminders.reminderlist.indices, id: \.self) { index in
                        NavigationLink(destination: DetailedRemView(superReminder : self.$superReminders.reminderlist[index] ).environmentObject(superReminders)) {
                            squareImageView(superReminder : self.$superReminders.reminderlist[index]).environmentObject(superReminders).environmentObject(superReminders)
                        }.listRowBackground(Color.clear)
                    }.onDelete { indexSet in
                        superReminders.reminderlist.remove(atOffsets: indexSet)}
                }

子视图声明;


import SwiftUI
struct DetailedRemView: View {
    var dateFormatter: DateFormatter {
          let formatter = DateFormatter()
        formatter.dateFormat = "EE, MMM d, YYYY"
          return formatter
      }
    @State public var showingDetail = false
    @Environment(\.colorScheme) var colorScheme: ColorScheme
    @State private var deleteReminderAlert = false
    @EnvironmentObject var superReminders : SuperReminders
    @Environment(\.presentationMode) var presentationMode
    @Binding var superReminder : SuperReminder
    @State private var showDialog = false
    @State var animate = false
    var body: some View {
            VStack{
                HStack(alignment: .center){
                    Text(superReminder.remdate)
                        .font(.title)
                        .multilineTextAlignment(.leading)
                        .padding(.leading)
                        .frame(minWidth: 100,maxWidth: .infinity, maxHeight: 50)
                    Spacer()
                    Button(action: {
                        self.showDialog.toggle()
                    }, label: {
                        ZStack{
                            RoundedRectangle(cornerRadius: 10)
                                .fill(Color.blue)
                                .frame(width: 80, height: 35)
                            HStack{
                                Text("Edit")
                                    .foregroundColor(.white)
                                    .multilineTextAlignment(.center)
                                    .cornerRadius(8)
                                Image(systemName: "pencil")
                                    .foregroundColor(.white)
                            }
                        }
                        .shadow(color:Color.gray.opacity(0.3), radius: 3, x: 3, y: 3)
                        .padding(.leading)
                                .alert(isPresented: $showDialog,
                                TextAlert(title: "Edit reminder title",
                                          message: "Enter a new title or dissmis.", placeholder: superReminder.remdate,
                                              keyboardType: .default) { result in
                                  if let text = result {
                                    if text != "" {
                                        superReminder.remdate = text }
                                    else{}
                                  } else {
                                  }
                                })
                    })
                    .padding(.leading)
                }
                .frame(minWidth: 100, maxWidth: /*@START_MENU_TOKEN@*/.infinity/*@END_MENU_TOKEN@*/, maxHeight: 50, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
                .padding(.vertical, -10)
                ZStack(alignment: .topTrailing){
                    Image(superReminder.image)
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(minWidth: 0,maxWidth: .infinity,minHeight: 200,maxHeight: .infinity)
                        .saturation(superReminder.pastreminder ? 0.1 : 1)
                        .clipShape(Rectangle())
                            .cornerRadius(10)
                        .padding(.all)
                        .pinchToZoom()
                    HStack{
                        Text(superReminder.dateactual, formatter: dateFormatter)
                            .foregroundColor(.white)
                            .frame(width: 180, height: 30, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
                            .background( superReminder.pastreminder ? Color.gray : Color.lightlygreen)
                            .cornerRadius(8)
                            .animation(/*@START_MENU_TOKEN@*/.easeIn/*@END_MENU_TOKEN@*/)
                        if superReminder.pastreminder == true {
                        ZStack{
                            RoundedRectangle(cornerRadius: 8)
                                .fill(Color.black)
                                .frame(width: 30, height: 30)
                            Image(systemName: "moon.zzz")
                                .foregroundColor(.white)
                        }.offset(x: animate ?  -3 : 0)
                        .onAppear(perform: {
                            shake()
                        })
                        }
                        else{}
                        }
                    .zIndex(0)
                    .offset(x: -10, y: 10)
                    .padding()
                    }
                .zIndex(1)
                .shadow(color: Color.gray.opacity(0.4), radius: 3, x: 1, y: 2)
                HStack{
                    Button(action: {
                        self.showingDetail.toggle()
                    }){
                    ZStack{
                        RoundedRectangle(cornerRadius: 10)
                            .fill(Color.lightlygreen)
                            .frame(width: 140, height: 40)
                        HStack{
                            Text("Reschedule")
                                .foregroundColor(.white)
                                .multilineTextAlignment(.center)
                                .cornerRadius(8)
                            Image(systemName: "calendar")
                                .foregroundColor(.white)
                        }
                    }
                    .shadow(color:Color.gray.opacity(0.3), radius: 3, x: 3, y: 3)
                    .padding(.all, 4.0)
                    }
                        .sheet(isPresented: $showingDetail, content :{
                                remdatepicker(isPresented: self.$showingDetail, superReminder: $superReminder)})
                    Button(action: {
                        if superReminder.pastreminder == true {
                            superReminder.pastreminder = false
                        }
                        else if superReminder.pastreminder == false{
                            superReminder.pastreminder = true
                        }
                    }, label: {
                        ZStack{
                            RoundedRectangle(cornerRadius: 10)
                                .fill(superReminder.pastreminder == true ? Color.lightlyblue : Color.gray)
                                .frame(width: 100, height: 40)
                            HStack{
                                Text(superReminder.pastreminder == true ? "Activate" : "Silence")
                                    .foregroundColor(.white)
                                    .multilineTextAlignment(.center)
                                    .cornerRadius(8)
                                Image(systemName: superReminder.pastreminder == true ? "checkmark.circle" : "moon.zzz")
                                    .foregroundColor(.white)
                                    }

                        }
                        .shadow(color:Color.gray.opacity(0.3), radius: 3, x: 3, y: 3)
                        .padding(.all, 4.0)
                    })
                    Button(action: {
                        self.deleteReminderAlert.toggle()
                    }, label: {
                        ZStack{
                            RoundedRectangle(cornerRadius: 10)
                                .fill(Color(.red))
                                .frame(width: 40, height: 40)
                            HStack{
                                Image(systemName: "trash")
                                    .foregroundColor(.white)
                            }
                        }
                        .shadow(color:Color.gray.opacity(0.3), radius: 3, x: 3, y: 3)
                        .padding(.all, 4.0)
                        })
                }.padding(.bottom, 20)
                .alert(isPresented: $deleteReminderAlert){
                        Alert(
                          title: Text("Are you sure?"),
                          message: Text("Do you want to delete this reminder?"),
                            primaryButton: .destructive(Text("Yes"), action: {
                                superReminders.remove(superReminder: superReminder)
                                self.presentationMode.wrappedValue.dismiss()
                            }),
                          secondaryButton: .cancel(Text("No"))
                )
            }
        }
    }
    func shake()  {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            withAnimation(Animation.default.repeatCount(6).speed(7)){
                animate.toggle()}}}
}

Class 和列表;


import SwiftUI

struct SuperReminder: Identifiable, Codable, Equatable {
    var id = UUID()
    var remdate = ""
    var dateactual = Date.init()
    var image  = "New1"
    var pastreminder = false
}

class SuperReminders: ObservableObject {
    @Published var reminderlist: [SuperReminder]
    
    init() {
        self.reminderlist = [
        ]
    }
    func add(superReminder: SuperReminder) {
            reminderlist.append(superReminder)
        }

        func remove(superReminder: SuperReminder) {
            if let index = reminderlist.firstIndex(of: superReminder) {
                reminderlist.remove(at: index)
            }
        }
}

这个答案类似于


SuperReminder: Identifiable, Codable, Equatable 以来循环 superReminders.reminderlist

ForEach(superReminders.reminderlist) { superReminder in
  NavigationLink(destination: DetailedRemView(superReminders: superReminders,
                                              superReminder: superReminder)) {
    -----
  }
}

DetailedRemView 中,执​​行以下操作:

struct DetailedRemView: View {

    @ObservedObject var superReminders : SuperReminders
    
    var superReminder : SuperReminder
    
    // find index of current superReminder   
    var indexOfReminder: Int? {
        superReminders.reminderlist.firstIndex {[=11=] == superReminder}
    }
    
    var body: some View {
        // Unwrap indexOfReminder
        if let index = indexOfReminder {
            VStack {
               ------ 
            }
        }
    }


    ----

}

在需要更新 superReminder 的地方使用 DetailRemView 中的 superReminders.reminderlist[index]

superReminders.reminderlist[index].pastreminder = false