问题描述
希望你度过一个比我更愉快的夜晚!
所以正如我在标题中提到的,每当我尝试从原始列表中删除一个带有绑定的项目时,我的 for each 循环就会崩溃。我做了一些研究,问题是每个视图都会生成一个带有 id 的视图,但是当您删除子视图中的项目时,它找不到内容并崩溃。返回“线程 1:致命错误:索引超出范围”。我可以通过声明 @State var 而不是 @Binding 来解决这个问题,这确实有效!但是,我的子视图中不止有一个删除按钮,如果我不使用绑定声明,所做的更改不会反映在主视图上。我不想放弃删除按钮和按钮。有没有办法将所有这些都保留在我的子视图中?
主视图声明;
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,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),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),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),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),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()}}}
}
类和列表;
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)
}
}
}
解决方法
这个答案类似于 Accessing and manipulating array item in an EnvironmentObject
从 superReminders.reminderlist
开始循环遍历 SuperReminder: Identifiable,Codable,Equatable
。
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 {$0 == superReminder}
}
var body: some View {
// Unwrap indexOfReminder
if let index = indexOfReminder {
VStack {
------
}
}
}
----
}
在需要更新 superReminder 的任何位置使用 superReminders.reminderlist[index]
中的 DetailRemView
。
superReminders.reminderlist[index].pastreminder = false