I’ve an app the place a consumer can create occasions for cities. The consumer is ready to choose a date and time for every occasion.
On town’s web page, the consumer is ready to see all of their occasions and can be in a position to set the date and time of every occasion. The town’s web page is split into two sections: unorganized occasions and arranged occasions. Unorganized occasions are merely occasions with no date set.
So when the consumer navigates to town web page, my API returns two arrays: an array of unorganized occasions and an array of organized occasions.
When the consumer units the date of an unorganized occasion, it strikes the occasion to the organized occasions array.
Moreover, on town web page, the consumer is ready to create a brand new occasion which routinely will get added to the unorganized occasions array.
Nevertheless, I am working right into a crash which occurs when:
- Consumer creates a brand new occasion
- Consumer faucets on that new occasion
- Units the date (which provides it to the organized occasions array)
- Units the time (right here it crashes)
The error is:
Thread 1: Deadly error: Index out of vary
I imagine it might should do with the truth that the Binding is not maintained and it may well’t discover the occasion as soon as it has been moved from the unorganized occasions array to the organized occasions array.
Right here is my code. I’ve disregarded among the unimportant bits.
MyApp class which acts as the one supply of reality:
@essential
struct MyApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject var cityManager = CityManager(cityService: CityService())
var physique: some Scene {
WindowGroup {
NavigationView {
MainView()
.environmentObject(cityManager)
}
}
}
}
The HomeView the place I present a listing of cities:
struct HomeView: View {
@StateObject personal var vm = HomeViewModel(homeService: HomeService())
@Binding var tabSelection: Int
@EnvironmentObject var cityManager: CityManager
var physique: some View {
NavigationStack {
ScrollView(showsIndicators: false) {
VStack(spacing: 0) {
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .prime, spacing: 32) {
ForEach($cityManager.cities, id: .id) { $metropolis in
CityItem(metropolis: $metropolis, axes: .horizontal)
}
}
}
}
}
}
.onAppear {
vm.fetchHome()
}
.onChange(of: vm.cities?.rely) {
cityManager.cities = vm.cities ?? []
}
.environmentObject(cityManager)
}
}
CityItem:
struct StadiumItem: View {
@Binding var metropolis: Metropolis
var physique: some View {
NavigationLink(vacation spot: CityPageView(metropolis: $metropolis)) {
VStack {
Textual content(metropolis.title)
}
}
}
}
CityPageView, which is the primary web page that exhibits all the occasions going down within the metropolis:
struct CityPageView: View {
@Binding var metropolis: Metropolis
@EnvironmentObject var cityManager: CityManager
@StateObject var cityPageViewModel = CityPageViewModel()
var physique: some View {
NavigationView {
ZStack(alignment: .prime) {
ScrollViewReader { worth in
ScrollView(showsIndicators: false) {
VStack(spacing: 0) {
// Checklist of unorganized occasions
UnorganizedEventsView(metropolis: $metropolis)
// Checklist of organized occasions
OrganizedEventsView(days: $metropolis.organizedEvents)
}
}
}
}
}
.environmentObject(cityManager)
.environmentObject(cityPageViewModel)
}
}
struct UnorganizedEventsView: View {
@Binding var metropolis: Metropolis
var physique: some View {
let unorganizedEvents = $metropolis.unorganizedEvents
if (!unorganizedEvents.isEmpty) {
VStack(alignment: .main, spacing: 0) {
Textual content("Unorganized")
LazyVStack(spacing: 0) {
ForEach(unorganizedEvents, id: .id) { $occasion in
EventView(
occasion: $occasion,
isLast: occasion == unorganizedEvents.wrappedValue.final
)
}
}
}
.id("Unorganized")
}
}
}
struct OrganizedEventsView: View {
@Binding var days: [Day]
var physique: some View {
ForEach($days, id: .id) { $day in
VStack(alignment: .main, spacing: 0) {
Textual content(day.date.toDayDate() ?? "")
LazyVStack {
ListEventsView(occasions: $day.occasions)
}
}
.id(day.date)
}
}
}
Right here is my Metropolis mannequin class:
struct Metropolis: Codable, Identifiable {
var id: Int
var title: String
var occasions: [Event]? {
didSet {
self.unorganizedEvents = self.getUnorganizedEvents()
self.organizedEvents = self.getOrganizedEvents()
}
}
var unorganizedEvents: [Event] = []
var organizedEvents: [Day] = []
enum CodingKeys: String, CodingKey {
case id = "id"
case title = "title"
case occasions = "occasions"
}
init(id: Int, title: String, occasions: [Event] = [], unorganizedEvents: [Event] = []) {
self.id = id
self.title = title
self.occasions = occasions
self.unorganizedEvents = unorganizedEvents
}
init(from decoder: Decoder) throws {
let container = attempt decoder.container(keyedBy: CodingKeys.self)
self.id = attempt container.decode(Int.self, forKey: .id)
self.title = attempt container.decode(String.self, forKey: .title)
self.occasions = attempt container.decodeIfPresent([Event].self, forKey: .occasions) ?? []
self.unorganizedEvents = self.getUnorganizedEvents()
self.organizedEvents = self.getOrganizedEvents()
}
func getUnorganizedEvents() -> [Event] {
return occasions?.filter({ $0.date == nil }) ?? []
}
func getOrganizedEvents() -> [Day] {
guard let occasions = occasions else {
return []
}
var eventsByDay: [String: [Event]] = [:] // Dictionary to retailer occasions grouped by date
// Group occasions by date
for occasion in occasions {
if let date = occasion.date {
if var eventsOnDate = eventsByDay[date] {
eventsOnDate.append(occasion)
eventsByDay[date] = eventsOnDate
} else {
eventsByDay[date] = [event]
}
}
}
// Create Day situations for every group of occasions
var days: [Day] = []
for (date, occasions) in eventsByDay {
let sortedEvents = occasions.sorted { ($0.timeStart ?? "24:59:59") < ($1.timeStart ?? "24:59:59") }
let day = Day(date: date, occasions: sortedEvents)
days.append(day)
}
days.kind { $0.date < $1.date }
return days
}
}
What am I doing fallacious that might trigger this crash?