NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

SOLVED: List with dynamic sections by date

Forums > SwiftUI

Hi guys,

I'm losing my mind a bit trying to figure out how to create some sections based on the day component of a day but no luck. I have tried multiple methods but I'm getting stuck every time, I would appreciate any hint. Last time I tried with a dictionary and I realise that the flaw lies in the Date proprety having such a granularity that every moment is different from the other but I can't think of anything else. Thank you!

Struct:

struct Scan: Identifiable, Codable, Comparable {
    var id = UUID()
    var scanDate = Date()
    let content: String

    static func < (lhs: Scan, rhs: Scan) -> Bool {
        return lhs.scanDate < rhs.scanDate
    }
}

View:

struct History: View {
    @EnvironmentObject var modelData: ModelData

    var groupedByDate: [Date: [Scan]] {
        Dictionary(grouping: modelData.scans, by: {$0.scanDate})
    }

    var headers: [Date] {
        groupedByDate.map({ $0.key }).sorted()
    }

    var body: some View {
        List {
            ForEach(headers, id: \.self) { header in
                Section(header: Text(header, style: .date)) {
                    ForEach(groupedByDate[header]!) { scan in
                        Text(scan.content)
                    }
                }
            }
        }
    }

Screenshot with the result :( https://postimg.cc/0KjChTHT

edit, I tried with scanDate as a computed proprety as well but it changes the value to all my previous saved object also :(

struct Scan: Identifiable, Codable, Comparable {
    var id = UUID()
    var scanDate: Date {
        let now = Date()
        let components = Calendar.current.dateComponents([.year, .month, .day], from: now)
        let date = Calendar.current.date(from: components)
        return date!
    }
    let content: String

    static func < (lhs: Scan, rhs: Scan) -> Bool {
        return lhs.scanDate < rhs.scanDate
    }
}

Edit2: Solved it by refering to another proprety outside the computed proprety like this:

struct Scan: Identifiable, Codable, Comparable {
    var id = UUID()
    var now = Date()
    var scanDate: Date {
        let components = Calendar.current.dateComponents([.year, .month, .day], from: now)
        let date = Calendar.current.date(from: components)
        return date ?? Date()
    }
    let content: String

    static func < (lhs: Scan, rhs: Scan) -> Bool {
        return lhs.scanDate < rhs.scanDate
    }
}

1      

hi,

you might consider turning all raw dates into the start of the day date:

var scanDate: Date { Calendar.current.startOfDay(for: date) }

now your dictionary grouping by scanDate should work OK.

  • one caveat: i think that the start of the date of this post (17-Apr-2021) is 12:00:00 AM, which might be shown 16-Apr-2021. if that's the case, just add 1 (second) to startOfDay(for: date) before returning the scanDate.

hope that helps,

DMG

2      

Turns out you're right, it works this way too. Thank you DMG! edit: it's not the case to add one second after 12.00 AM

1      

Hacking with Swift is sponsored by Play

SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!

Click to learn more about Play!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.