0

I'm getting response from API's but I am not able to get emails array back, what am I doing wrong? I tried to add DispatchQueue.main.asyn { emails.append(result.data.email) } but its the same result.

// MARK: - Response Class
struct Response: Codable {
    let data: DataClass
    let support: Support
}

// MARK: - DataClass
struct DataClass: Codable {
    let id: Int
    let email, firstName, lastName: String
    let avatar: String

    enum CodingKeys: String, CodingKey {
        case id, email
        case firstName = "first_name"
        case lastName = "last_name"
        case avatar
    }
}

// MARK: - Support
struct Support: Codable {
    let url: String
    let text: String
}

let urls = [
    URL(string: "https://reqres.in/api/users/1"),
    URL(string: "https://reqres.in/api/users/3"),
    URL(string: "https://reqres.in/api/users/10")
]


func getEmailFromAPI(urls: [URL?]) -> [String] {
    var emails: [String] = []
    for url in urls {
        URLSession.shared.dataTask(with: URLRequest(url: url!)) { data, response, error in
            guard let data = data else { return }
            guard let result = try? JSONDecoder().decode(Response.self, from: data) else { return }
            print(result.data.email)
            emails.append(result.data.email)
        }.resume()
    }
    return emails
}

print(getEmailFromAPI(urls: urls))

Please advice as to what am I doing wrong, Thanks.

nitpaxy
  • 67
  • 10
  • You have asynchronous code (inside data task handler) that you are expecting to behave synchronously. The newest fix is to switch to `async await` it is the "better" option but you should to research on completion handlers. – lorem ipsum Oct 20 '22 at 13:31
  • It's the asynchronous concept your are missing. Replace `print(result.data.email)` with `print("Inside closure: \(result.data.email)')`, and `return emails` with `print("outside closure: \(emails)"); return emails` . Which one did you expect to be printed first? – Larme Oct 20 '22 at 13:39

1 Answers1

0

"return emails" statement will get executed before your array gets loaded with data because of the async operation.

So you can use closure to pass the emails as per below

func getEmailFromAPI(urls: [URL?], emailResult: @escaping ([String]?) -> Void) {
        var emails: [String] = []
        for url in urls {
            URLSession.shared.dataTask(with: URLRequest(url: url!)) { data, response, error in
                if error != nil {
                    emailResult(nil)
                }else {
                    guard let data = data else { return }
                    print(result.data.email)
                    emails.append(result.data.email)
                    emailResult(emails)
                }
            }.resume()
        }
    }

Suggestion - prefer to not append email operation instead create a codable object for the same

teja_D
  • 383
  • 3
  • 18