0

I have an array of users returned. I want to group them by created date and then display them in SwiftUI List with sections. The section title is the date. After I group the users I end up with a Dictionary of user arrays and the key is the date that group all users that have been created in the same date I want to use the key as a section and the value (user array) as List rows. It seems that List only works with array. Any clean solution to prepare the data for the List so it can display the sections and its content ?

import SwiftUI
import Combine

struct ContentView: View {
    @EnvironmentObject var interactor: Interactor

    var body: some View {
        List(interactor.users) { user in // Error: Cannot convert value of type '[String : [User]]' to expected argument type 'Range<Int>'
             
        }
        .onAppear {
            interactor.loadUsers()
        }
    }
}


class Interactor: ObservableObject {
    @Published private(set) var users = [String: [User]]()

    func loadUsers() {
        let allUsers = [User(id: "1", name: "Joe", createdAt: Date()),
                        User(id: "2", name: "Jak", createdAt: Date())]

        users = Dictionary(grouping: allUsers) { user in
            let dateFormatted = DateFormatter()
            dateFormatted.dateStyle = .short
            return dateFormatted.string(from: user.createdAt)
        }
    }
}

struct User: Identifiable {
    let id: String
    let name: String
    let createdAt: Date
}

iOSGeek
  • 5,115
  • 9
  • 46
  • 74
  • Does this answer your question: https://stackoverflow.com/questions/56675532/swiftui-iterating-through-dictionary-with-foreach – nicksarno Feb 11 '21 at 14:50
  • Not really. I'm looking for what us the better data stricture that I can use to be able to map it to a list with sections – iOSGeek Feb 11 '21 at 16:03

1 Answers1

0

You can use sections inside List, and make use of its header parameter to pass Dates. I have already fetched all dates as [String] by using separate function. One thing you need to figure is the way you are going to pass multiple keys to fetch data for different date keys that you will have. May be you can create that first by using [Users] objects and save all keys.

Below is the solution to your issue-:

ContentView-:

////  Created by TUSHAR SHARMA on 06/02/21.
////
//
import SwiftUI


struct ContentView: View {
    @EnvironmentObject var interactor: Interactor
    
    var body: some View {
        
        List {
            ForEach(getAllDates(),id:\.self) { dates in
                Section(header: Text(dates)) {
                    ForEach(interactor.users[dates] ?? []) { users in
                        Text(users.name)
                    }
                }
            }
        }
    }
    
    func getAllDates() -> [String]{
        let getObjects = interactor.users[Date().stringFromDate()] ?? []
        var dateArray : [String] = []
        for getData in getObjects{
            dateArray.append(getData.createdAt.stringFromDate())
        }
         let unique = Array(Set(dateArray))
         return unique
    }
}

extension Date{
    func stringFromDate() -> String{
        let dateFormatted = DateFormatter()
        dateFormatted.dateStyle = .short
        return dateFormatted.string(from: self)
    }
}


class Interactor: ObservableObject {
    @Published private(set) var users = [String: [User]]()
    
    init() {
        loadUsers()
    }
    
    func loadUsers() {
        let allUsers = [User(id: "1", name: "Joe", createdAt: Date()),
                        User(id: "2", name: "Jak", createdAt: Date())]
        
        users = Dictionary(grouping: allUsers) { user in
             user.createdAt.stringFromDate()
        }
    }
}

struct User: Identifiable {
    let id: String
    let name: String
    let createdAt: Date
}

@main view

//  Created by TUSHAR SHARMA on 07/01/21.
//

import SwiftUI

@main
struct WaveViewApp: App {
    let interactor = Interactor()
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(interactor)
        }
    }
}
Tushar Sharma
  • 2,839
  • 1
  • 16
  • 38