简体   繁体   中英

Swift Concurrency UIButton

Is it possible to use async/await for POST HTTP requests in UIKit, namely a from UIButton ?

I can get the request sent but then it immediately crashes. Working perfectly using URLSession , using this as a learning experience.

lazy var buttonTest: UIButton = {
    let button = UIButton()
    button.addTarget(self, action: #selector(testAsyncTwo), for: .touchUpInside)
    return button
}()

@objc func testAsync() async throws {
    let date = Date()
    let df = DateFormatter()
    df.dateFormat = "yyyy-MM-dd HH:mm:ss"
    let dateString = df.string(from: date)

    let json: [String: Any] = ["item": "1",
                               "time": "\(dateString)"]
    let jsonData = try? JSONSerialization.data(withJSONObject: json)
    
    guard let url = URL(string: "https://myapiendpoint.com/api/") else { fatalError("Missing URL") }
    var urlRequest = URLRequest(url: url)
    let token: String = "mySecretKey"
    urlRequest.setValue("Token \(token)", forHTTPHeaderField: "Authorization")
    urlRequest.httpMethod = "POST"
    urlRequest.setValue("\(String(describing: jsonData?.count))", forHTTPHeaderField: "Content-Length")
    urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
    urlRequest.httpBody = jsonData
    let (data, response) = try await URLSession.shared.data(for: urlRequest)
    
    guard (response as? HTTPURLResponse)?.statusCode == 200 else { fatalError("Error while fetching data") }
    let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
    if let responseJSON = responseJSON as? [String: Any] {
        print(responseJSON) //Code after Successfull POST Request
    }
}

Thanks very much!

The crash is unrelated to your URLSession code. The problem is that you have declared the button's selector to be asynchronous throwing function. That is incompatible with an @objc selector.

Replace:

@objc func testAsync() async throws { 
    ... 
}

With:

@objc func didTapButton(_ sender: Any) {
    Task {
        try await testAsync()
    }
}

func testAsync() async throws {
    ...
}

The key observation is that the @objc method is not an asynchronous function. I would also give the button handler a sender parameter and a more descriptive name, to follow established conventions and make it clear at a glance that it is handling a button tap.

Obviously, when you do this, you will have to change the #selector reference, too:

button.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside)

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