arraysswiftsortingswiftuiswiftdata

Problem with the way the .suffix works with SwiftData


Ok, I have a subview, which should just show 2 last readings...

I understand, that I can actually do .last and or just do $0 and $1, but I wanted to do it in an elegant way, so my code is:

import SwiftUI
import SwiftData

struct LastReadingsView: View {
    
    var readings: [Reading]?
        
        var body: some View {
            if let readings = readings?.sorted(by: { $0.date > $1.date }) {
                
                let lastTwoReadings = readings.suffix(2)
                
                ForEach(lastTwoReadings) { reading in
                    ReadingRow(reading: reading)
                }
            } else {
                Text("No readings available")
                    .foregroundColor(.gray)
            }
        }
}

#Preview {
    LastReadingsView()
}

But, it doesn't do the last two readings in an already sorted array, it takes some two elements and that is it...

Do I miss something? I know, that SwiftData is not good with array sorting, but not THAT bad?!


Solution

  • Although your code works for me in my tests, you could try this approach without using intermediate declarations in the body of the view.

    struct LastReadingsView: View {
        let readings: [Reading]?
        
        var body: some View {
            if readings != nil {
                ForEach(readings!.sorted(by: { $0.date > $1.date }).suffix(2)) { reading in
                    ReadingRow(reading: reading)
                }
            } else {
                Text("No readings available")
                    .foregroundColor(.gray)
            }
        }
    }
    

    EDIT-1:

    here is my full test code:

    // for testing
    @Model class Reading {
        var date: Date
        var digits: Int
        
        init(date: Date, digits: Int) {
            self.date = date
            self.digits = digits
        }
    }
    
    struct ContentView: View {
        // for testing
        let readingArr = [
            Reading(date: Date(), digits: 1),
            Reading(date: Date().addingTimeInterval(60*60*24*1), digits: 2),
            Reading(date: Date().addingTimeInterval(60*60*24*2), digits: 3),
            Reading(date: Date().addingTimeInterval(60*60*24*3), digits: 4),
            Reading(date: Date().addingTimeInterval(60*60*24*4), digits: 5)
        ]
        var body: some View {
            LastReadingsView(readings: readingArr)
        }
    }
    
    // test code
    struct LastReadingsView: View {
        let readings: [Reading]?
        
        var body: some View {
            if readings != nil {
                ForEach(readings!.sorted(by: { $0.date > $1.date }).suffix(2)) { reading in
                    ReadingRow(reading: reading)
                }
            } else {
                Text("No readings available")
                    .foregroundColor(.gray)
            }
        }
    }
    
    // for testing
    struct ReadingRow: View {
        let reading: Reading
        
        var body: some View {
            Text("\(reading.digits)")
        }
    }