Swift Chart causing app to crash when deleting an item from the data array

When deleting the last added item from a list view in my app a bar chart in a different view crashes my app. If I delete any other item in the list view everything work as expected. I'm using SwiftData in my app.

Does anyone have any idea how I can prevent the app from crashing?

I filter the data in the init to only have the current days data

Chart View

struct ConsumedDrinkChartView: View {
  @Environment(\.modelContext) var modelContext
  
  let screenVerticalSizeClass = UIScreen.VerticalSizeClass
  var compactScreen: Bool {
    return screenVerticalSizeClass == "compact"
  }
  
  @State private var chartCalendarUnit: Calendar.Component = .hour
  @State private var chartRange: ClosedRange<Date>
  @State private var axisValueLabelFormat: Date.FormatStyle
  @State private var axisValueLabelCount: Int
  @State private var startDate: Date
  @State private var endDate: Date
  @State private var plotStartPadding: Double = 0
  @State private var plotEndPadding: Double = 0
  
  @Binding var selectedTimeFrame:String
  
  @Query var consumedFluids: [ConsumedDrink]
  
  let defaultVolume = DataStore.defaultVolume
    
  init(selectedTimeFrame: Binding<String>, dateRange: ClosedRange<Date>) {
    _selectedTimeFrame = selectedTimeFrame
    _startDate = State(initialValue: Date().startOfDay)
    _endDate = State(initialValue: Date().endOfDay)
    
    let endDate = dateRange.upperBound
    let startDate = dateRange.lowerBound

    _consumedFluids = Query(filter: #Predicate {
      $0.date > startDate && $0.date < endDate
    }, sort: \ConsumedDrink.date)
    
    _chartRange = State(initialValue: dateRange)
    _axisValueLabelFormat = State(initialValue: .dateTime.hour(.conversationalDefaultDigits(amPM: .narrow)))
    _axisValueLabelCount = State(initialValue: 2)
  }
  
  var body: some View {
    Chart {
      ForEach(consumedFluids) { consumedFluid in
        BarMark(x: .value("Date", consumedFluid.date, unit: chartCalendarUnit),
                y: .value("Fluid Ounces", consumedFluid.drink.amount))
      }
      .foregroundStyle(.pink)
      
    }
    .frame(height: 180)
    .padding()
    .chartXAxis {
      AxisMarks(values: .stride(by: chartCalendarUnit, count: axisValueLabelCount,roundLowerBound: true, roundUpperBound: true)) { _ in
        AxisGridLine()
        AxisValueLabel(format: axisValueLabelFormat, centered: true)
      }
    }
    .chartXScale(domain: chartRange, range: .plotDimension(startPadding: plotStartPadding, endPadding: plotEndPadding))
    .background(RoundedRectangle(cornerRadius: 12).fill(Color(.secondarySystemBackground)))
    .onChange(of: selectedTimeFrame) {
      selectChartRange()
    }
    .onChange(of: consumedFluids) {
      print("consumedFluids: \(consumedFluids.count)")
    }
    .onAppear {
      selectChartRange()
    }
  }
    
  func selectChartRange() {
    plotStartPadding = 0
    plotEndPadding = 0
    
    switch selectedTimeFrame {
      case "Day":
        startDate = Date().startOfDay
        endDate = Date().endOfDay
        chartCalendarUnit = .hour
        axisValueLabelCount = 2
        axisValueLabelFormat = .dateTime.hour(.conversationalDefaultDigits(amPM: .narrow))
      case "Week":
        startDate = Date().add(days: -7)
        chartCalendarUnit = .day
        axisValueLabelCount = 1
        axisValueLabelFormat = .dateTime.weekday()
      case "Month":
        startDate = Date().add(days:  -30)
        chartCalendarUnit = .day
        axisValueLabelCount = 2
        axisValueLabelFormat = .dateTime.day()
        plotStartPadding = 10
        plotEndPadding = 10
      case "SixMonths":
        let endOfMonth = Date().endOfMonth()
        startDate = endOfMonth.add(months: -6)
        chartCalendarUnit = .month
        axisValueLabelCount = 1
        axisValueLabelFormat = .dateTime.month()
        plotStartPadding = 10
        plotEndPadding = 32
      case "Year":
        let endOfMonth = Date().endOfMonth()
        startDate = endOfMonth.add(months: -12)
        chartCalendarUnit = .month
        axisValueLabelCount = 1
        axisValueLabelFormat = .dateTime.month(.narrow)
        plotStartPadding = 15
        plotEndPadding = 15
      default:
        chartCalendarUnit = .day
    }
    chartRange = startDate...endDate
  }
}

List View

struct ConsumedDrinkListView: View {
  @Environment(\.modelContext) var modelContext
  @Query(sort: \ConsumedDrink.date) var dailyConsumedFluids: [ConsumedDrink]
  
  @State private var showingAlert = false
  @State private var alertMessage: String = ""
  @State private var alertTitle: String = ""
  
  var body: some View {
    NavigationStack {
      if dailyConsumedFluids.isEmpty {
        ContentUnavailableView("No Consumed Drinks", systemImage: "mug.fill", description: Text("Drink some water and stay hydrated."))
      } else {
        List {
          ForEach(dailyConsumedFluids, id: \.self) { consumedDrink in
            NavigationLink {
              EditConsumedDrinkView(consumedDrink: consumedDrink)
            } label: {
              ConsumedDrinkRowView(consumedDrink: consumedDrink)
            }
            .swipeActions{
              Button("Delete", systemImage: "trash", role: .destructive) {
                deleteConsumedDrink(consumedDrink: consumedDrink)
              }
              .tint(.red)
            }
          }
        }
        .listStyle(.plain)
        
        .alert(isPresented: $showingAlert) {
          Alert(title: Text(alertTitle),
                message: Text(alertMessage),
                dismissButton: .default(Text("OK"))
          )
        }
      }
      Text("")
      .navigationTitle("Consumed Drinks")
      .navigationBarTitleDisplayMode(.inline)
    }
  }
  
  func deleteConsumedDrink(consumedDrink: ConsumedDrink) {
    do {
      
      if modelContext.hasChanges {
        print("ConsumedDrinkListView.deleteConsumedDrink")
        print("modelContext has Changes. Saving modelContext")
        try modelContext.save()
      }
      
      try DataStore.deleteConsumedDrink(drink: consumedDrink, modelContext: modelContext)
    } catch {
      self.alertTitle = "Error deleting consumed drink - \(consumedDrink.drink.name)"
      self.alertMessage = error.localizedDescription
      self.showingAlert = true
    }
  }
}

@syclonefx Have you looked through the crash logs to determine the source of the crash and the error that was thrown ?

No, I haven't. I'll check them out. I'm still learning swift programming and the crash logs are a little confusing to me. I did try my app in Xcode 16 and it doesn't crash on the iOS 18 simulator.

Here are the errors I'm getting

This is on the ConsumedDrink

This is in the ConsumedDrinkChartView

import Foundation
import SwiftData

@Model
class ConsumedDrink {
  
  let id: UUID
  var drink: Drink
  var date: Date
  
  @Transient var volumeMeasure: VolumeMeasurement {
    let defaultVolume = DataStore.defaultVolume
    let drinkVolume = self.drink.volume
    let volume = drinkVolume.converted(to: defaultVolume.unit).value
    return VolumeMeasurement(date: self.date, value: volume, unit: defaultVolume.unit.symbol)
  }
  
  init(drink: Drink, date: Date = Date()) {
    self.id = UUID()
    self.drink = drink
    self.date = date
  }
}
Swift Chart causing app to crash when deleting an item from the data array
 
 
Q