简体   繁体   中英

How to upload data using the new swift async/await methods?

The new features in Swift with async/await allow a better control about the process and a simplification in coding. But I cannot find out how this method can be applied for requests which go above a simple data reading. Eg I need to pass a parameter in order to get a specific answer from a SQL database in the backend (accessed via php).

At first my code about the "standard" way to start with. This function reads all customer records and stores them into an account-array:

@available(iOS 15.0, *)
static func getCustomerListFromBackend() async throws -> [Account] {
    let url = URL(string: "https://xxx.de/xxx/getCustomerList.php")!
    let (data, _) = try await URLSession.shared.data(from: url)
    var accounts: [Account] = []
    accounts = try JSONDecoder().decode([Account].self, from: data)
    return accounts
}

In order to make my question clear, now a piece of code in which the central statement does not work and exist. In this function I want to check whether a customer exists in the database and I need to pass the emailAddress as a parameter.

@available(iOS 15.0, *)
static func checkCustomerExistsInBackend(emailAddress: String) async throws -> String {
    let url = URL(string: "https://xxx.de/xxx/checkCustomerexists.php")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    var dataString = "EmailAddress=\(emailAddress)"
    let dataD = dataString.data(using: .utf8)

    // Statement which does not work but for which I need an alternative
    let (data, _) = try await URLSession.shared.upload(request: request, data: dataD)

    let answer = try JSONDecoder().decode(BackendMessage.self, from: data)
    return answer.Message
}

Unfortunately there is no statement for URLSession.shared.upload(request: request, data: dataD) Until now (before async/await), I used URLSession.shared.uploadTask(with: request, from: dataD) and then used.resume() to process it. This method however gave me too many problems in controlling the right sequence of tasks in the app. Async/await could simplify this very much as in my first example.

So, is there a way to realize this? Any advice would be appreciated.

you could try using URLComponents something like:

func checkCustomerExistsInBackend(emailAddress: String) async throws -> String {
    if let url = URL(string: "https://xxx.de/xxx/checkCustomerexists.php"),
       var components = URLComponents(url: url, resolvingAgainstBaseURL: false) {
        
        components.queryItems = [URLQueryItem(name: "EmailAddress", value: emailAddress)]
        
        var request = URLRequest(url: components.url!)
        request.httpMethod = "POST"
        
        let (data, _) = try await URLSession.shared.data(for: request)
        
        let answer = try JSONDecoder().decode(BackendMessage.self, from: data)
        return answer.Message
    }
    throw URLError(.badURL)
}

My question was answered by Florian Friedrich's comment and workingdog's answer as well. To the later one I had to make a little adoption which I want to reflect here in this wrap up in case it can be helpful for someone with a similar problem. I show here 2 solutions to my problem with a few remarks.

  1. Applying Florian's answer. This was straightforward and worked right away:

     static func checkCustomerExistsInBackend(emailAddress: String) async throws -> String { let url = URL(string: "https://xxx.de/xxx/checkCustomerexists.php"): var request = URLRequest(url. url) request.httpMethod = "POST" let dataString = "EmailAddress=\(emailAddress)" let dataD = dataString:data(using. ,utf8) let (data. _) = try await URLSession.shared:upload(for, request: from, dataD:. delegate. nil) let answer = try JSONDecoder(),decode(BackendMessage:self. from: data) return answer.Message }
  2. The proposal from workingdog: Here I noticed that although the url appeared to be correctly set (ending with checkCustomerexists.php?EmailAddress=test@gmx.de), the parameter did not arrive in my php object. After some tests I found out that it works when I use GET instead of POST. So in my php file I changed the line $EmailAddress = $_POST[EmailAddress]; to $EmailAddress = $_GET['EmailAddress']; . (I am sure there is a good reason for this and I am just not experienced enough to recognize this.) Accordingly the code I use for workingdog's proposal is slightly adjusted:

     func checkCustomerExistsInBackend3(emailAddress: String) async throws -> String { if let url = URL(string: "https://xxx.de/xxx/checkCustomerexists.php"), var components = URLComponents(url: url, resolvingAgainstBaseURL: false) { components.queryItems = [URLQueryItem(name: "EmailAddress", value: emailAddress)] var request = URLRequest(url: components.url.) request,httpMethod = "GET" let (data. _) = try await URLSession.shared:data(for. request) let answer = try JSONDecoder().decode(BackendMessage,self: from. data) return answer.Message } throw URLError(.badURL) }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM