Search code examples
iosarraysjsonswiftalamofire

How to update array elements before calling that array in a ViewController


I am bringing data such as an user name from an API using Alamofire, I am trying to append the data I bring from the API to an array (users), and then, the numberOfRowsInSection in my table are the amount of items in the array, such as here:

var users: [User] = []
   
   func getUser(){
       
       AF.request("https://randomuser.me/api/?results=1", method: .get).validate(statusCode: statusOK).responseDecodable (of: UserResult.self){ response in
           if let user = response.value?.results{
               self.users = user
               print(user)
            // self.viewController.tableView.reloadData()
               print(user.first?.name?.first! ?? "Unknown")
               print(user.count)
           } else {
               print(response.error?.errorDescription ?? "No error")
           }
       }
   }

But then, when I run the app there are no cells, so I print users.count in the viewDidLoad where the table is located, and it prints 0, but if I print users.count in the getUser() function, it actually prints that there is 1 item in the array, as in here:

0
[Random_User_List.User(name: Optional(Random_User_List.Name(first: Optional("Fredi"))), email: "[email protected]", gender: Optional("male"), address: nil, phone: Optional("0488-7393469"))]
Fredi
1

So I'm assuming I have to load the info inside the users array before summoning the getUsers() function in the viewDidLoad, and I have tried to use a reloadData() in both View Controller's viewDidLoad() and after catching the data inside the array, and it didn't work either, in fact, it caused a EXC_BAD_ACESS in networkingProvider (Thread 1: EXC_BAD_ACCESS (code=2, address=0x16cd37fc0)):

    var networkingProvider = NetworkingProvider()

    override func viewDidLoad() {
        super.viewDidLoad()
        NetworkingProvider.shared.getUser()
        print(networkingProvider.users.count)
//        self.tableView.reloadData()
        tableView.dataSource = self
        tableView.delegate = self
        tableView.register(UINib(nibName: "CustomTableViewCell", bundle: nil), forCellReuseIdentifier: "myCustomCell")
    }

I will also leave my Model if that helps:

struct UserResult: Decodable{
    let results: [User]?
}

struct User: Decodable{
    var name: Name?
    var email: String
    var gender: String?
    var address: String?
    var phone: String?
}

struct Name: Decodable{
    var first: String?
}

Solution

  • func getUser(completion: @escaping (_ users:[User]?,_ error:Error?) -> Void){
       
       AF.request("https://randomuser.me/api/?results=1", method: .get).validate(statusCode: statusOK).responseDecodable (of: UserResult.self){ response in
           if let user = response.value?.results{
              completion(user, nil) // if array other wise change the completion argument to single object
           } else {
               print(response.error?.errorDescription ?? "No error")
               completion(nil, error) 
           }
       }
    

    }

    and reload the table after getting user

     override func viewDidLoad() {
        super.viewDidLoad()
       
        NetworkingProvider.shared.getUser { users, error in
              if let users = users {
                     self.users = users
                     self.tableView.reloadData() // or you can use didSet of array to reload Data
              }
         }
      
    }
    

    Using didSet to reload

    var users: [User] = [] {
        didSet {
            tableView.reloadData() // if you using this then you don't need to reload in viewdidload closure 
        }
    }