简体   繁体   English

如何使用新的 swift async/await 方法上传数据?

[英]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. Swift 中带有 async/await 的新特性允许更好地控制流程并简化编码。 But I cannot find out how this method can be applied for requests which go above a simple data reading.但是我无法找到这种方法如何应用于 go 以上简单数据读取的请求。 Eg I need to pass a parameter in order to get a specific answer from a SQL database in the backend (accessed via php).例如,我需要传递一个参数以便从后端的 SQL 数据库(通过 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:这个 function 读取所有客户记录并将它们存储到一个帐户数组中:

@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.在这个 function 中,我想检查数据库中是否存在客户,我需要将 emailAddress 作为参数传递。

@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.不幸的是没有声明URLSession.shared.upload(request: request, data: dataD) URLSession.shared.uploadTask(with: request, from: dataD) () 来处理它。 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. async/await 可以像我的第一个例子一样简化这个。

So, is there a way to realize this?那么,有没有办法实现这一点? Any advice would be appreciated.任何意见,将不胜感激。

you could try using URLComponents something like:您可以尝试使用URLComponents类的东西:

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. Florian Friedrich 的评论和 workingdog 的回答也回答了我的问题。 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.我在这里通过一些评论展示了我的问题的 2 个解决方案。

  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.来自 workingdog 的建议:在这里,我注意到虽然 url 似乎已正确设置(以 checkCustomerexists.php?EmailAddress=test@gmx.de 结尾),但参数并未到达我的 php object。经过一些测试,我发现当我使用 GET 而不是 POST 时它有效。 So in my php file I changed the line $EmailAddress = $_POST[EmailAddress];所以在我的 php 文件中,我更改了行$EmailAddress = $_POST[EmailAddress]; to $EmailAddress = $_GET['EmailAddress'];$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: (我确信这是有充分理由的,我只是没有足够的经验来认识到这一点。)因此,我对 workingdog 提案中使用的代码进行了轻微调整:

     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) }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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