arraysswiftuitableviewalamofireswifty-json

How do i populate three sections in a tableview with SwiftyJSON


I want to assign records or cells for 3 sections ["Managers","Accountants","Receptionist"] where key "authority" has the validation of which section it belongs to ..

Swift code:

struct GlobalVariables {
        static var userdetailsJSON: [JSON] = [JSON.null]
        static var sectionTitles: [String] = ["Managers","Accountants","Receptionist"]
}
@IBAction func Userdb_Btn(_ sender: Any) {
        let url = "http://.../GetUsers.php"
        let headers: HTTPHeaders = ["Content-Type":"application/x-www-form-urlencoded"]
        let data:  Parameters = ["Authorization":"IOSAPP"]
        AF.request(url, method: .post, parameters: data, encoding: URLEncoding.default, headers: headers).response { response in

            switch response.result {

                       case .success:
                        let json : JSON = JSON(response.data ?? JSON.null)
                        let jsonError = json["error"].boolValue

                        if jsonError ==  false{
                            UsersdbVC.GlobalVariables.userdetailsJSON = json["userDetails"].arrayValue
                            print(UsersdbVC.GlobalVariables.userdetailsJSON)
                        }else{
                            self.displayAlert(title: "Failed to load users data !", message:"")
                        }

                       case .failure(let error):
                        self.displayAlert(title: "Connection error", message: "\(error)")
            }
        }
   }

Here is my Json output:

[{
  "name" : "Oliver",
  "password" : "1234",
  "username" : "Ramy",
  "id" : 84560,
  "authority" : "Manager"
}, {
  "name" : "Maxwell",
  "password" : "1234",
  "username" : "Omar",
  "id" : 84561,
  "authority" : "Accountant"
}, {
  "name" : "Tom",
  "password" : "1234",
  "username" : "Ahmed",
  "id" : 84562,
  "authority" : "Accountant"
}]

Number of sections could be identified by :

func numberOfSections(in tableView: UITableView) -> Int {
return GlobalVariables.sectionTitles.count}

but how could we populate records for each section by validating itself from key "authority" .. ? let me explain, i should see in tableview as follows:

Section: Manager
Cell: ID: 84560 - Oliver

Section: Accountant
Cell: ID:84561 - Maxwell
Cell: ID:84562 - Tom

Section: Receptionist
Cell: Empty...

just like filtering or sorting by authority... Although, the following code populates the records but the same for each section... CellForRowAt:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "usersTVC", for: indexPath)
        let userID: String = GlobalVariables.userdetailsJSON[indexPath.row]["id"].stringValue
        let userName: String = GlobalVariables.userdetailsJSON[indexPath.row]["name"].stringValue
        cell.textLabel?.text = "ID: \(userID) - \(userName)"
       return cell
   }

numberOfRowsInSection:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return GlobalVariables.userdetailsJSON[section]["authority"].count
   }

Any help would be appreciated !


Solution

  • Forget SwiftyJSON, it's a great library but it's outdated.
    And forget also a struct with static properties as data source.

    Decode the JSON with Decodable – AlamoFire does support it – and group the array with Dictionary(grouping:by:) into sections.


    First create two structs, a struct for the sections and one for the items (User in the following example)

    struct Section {
        let name : String
        let users : [User]
    }
    
    struct User : Decodable {
        let name, password, username, authority : String
        let id : Int
    }
    

    This is a standalone solution without AF, create a data source array

    var sections = [Section]()
    

    Decode the JSON

    let jsonString = """
    [{
      "name" : "Oliver",
      "password" : "1234",
      "username" : "Ramy",
      "id" : 84560,
      "authority" : "Manager"
    }, {
      "name" : "Maxwell",
      "password" : "1234",
      "username" : "Omar",
      "id" : 84561,
      "authority" : "Accountant"
    }, {
      "name" : "Tom",
      "password" : "1234",
      "username" : "Ahmed",
      "id" : 84562,
      "authority" : "Accountant"
    }]
    """
    
    do {
        let users = try JSONDecoder().decode([User].self, from: Data(jsonString.utf8))
        let grouped = Dictionary(grouping: users, by: \.authority)
        sections = grouped.map(Section.init)
        
        print(sections)
    } catch {
        print(error)
    }
    

    The data source methods are

    func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections[section].users.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "usersTVC", for: indexPath)
        let user = sections[indexPath.section].users[indexPath.row]
        cell.textLabel?.text = "ID: \(user.id) - \(user.name)"
        return cell
    }
    

    Update: To decode the JSON with Alamofire use

    AF.request(url, method: .post, parameters: data, headers: headers).responseDecodable(of: [User].self, decoder: JSONDecoder()) { response in
        switch response.result {
            case .success(let users): 
               let grouped = Dictionary(grouping: users, by: \.authority)
               sections = grouped.map(Section.init)
            case .failure(let error): print(error)