iosjsonswifttableview

How to Fetch JSON to Swift to tableView as Sections and Rows?


I want to ask how to implement the files as sections depends on userId then show all again in the tableview.

I'm started build simple project I fetched JSON file as decoder and show all in table view:

func fetchUsers(using url: String){
    let url = URL(string: url)!
    let _ = URLSession.shared.dataTask(with: url){ (data,response,error)
        in
        guard let data = data else {return}
        do{
            let objects = try JSONDecoder().decode([User].self, from: data)  // decode * ( Codable )
            self.users = objects
        } catch{
            print("error loading data cause: \(error)")
            }
        }.resume()
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if let cell = tableView.dequeueReusableCell(withIdentifier: "users",for: indexPath) as? customeCellTableViewCell{
        let indexRow = users[indexPath.row]
        cell.dataModel(forModel: indexRow)
     return cell
    }
    return UITableViewCell()
}

private func numberOfUsers(in users: [User]) -> Int {
         
            return 1
        }
    
        func numberOfSections(in tableView: UITableView) -> Int {

            return numberOfUsers(in: self.users)
            
        }

Solution

  • Like @vadian mentions tuples should be avoided for this so here is an improved solution.

    Instead of a tuple we can use a struct to hold the grouped data

    struct UsersByID {
        let id: Int
        var users : [User]
    }
    

    then change the load function to

    func load(withUsers users: [User]) {
        let dict = Dictionary(grouping: users) { return $0.userID }
        usersByID = dict.map { (key, values) in
            return UsersByID(id: key, users: values)
        }.sorted(by: { $0.id < $1.id })
    }
    

    The rest of the code is the same but replace key with id and value with users


    Old solution

    First create a dictionary to hold your sections (keys) and rows (values) as a property in the view controller

    var usersByID = [(key: Int, value: [User])]()
    

    then fill that dictionary using grouping:by: using the array from json

    func load(withUsers users: [User]) {
        usersByID = Dictionary(grouping: users, by: { user in
            user.userID }).sorted(by: { $0.0 < $1.0})
    }
    

    then the table view functions use this dictionary


    override func numberOfSections(in tableView: UITableView) -> Int {
        return usersByID.count
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return usersByID[section].value.count
    }
    
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return String(usersByID[section].key)
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell", for: indexPath)
    
        let user = usersByID[indexPath.section].value[indexPath.row]
        cell.textLabel?.text = user.title
        //...
    
        return cell
    }