swiftclosuresurlsession

"Cannot convert return expression of type '()' to return type 'String'" compiler error when trying to access returned string from closure


func requestList(completionParameter: @escaping (String) -> String ) {
    let url = URL(string: "https://www.google.de")!
    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        if let error = error {
            let message = error.localizedDescription
            completionParameter(message)
        }
        if let response = response {
            let message = response.mimeType!
            completionParameter(message)
        }
    }
    task.resume()
}

func printer() -> String {
    let dspmsg = requestList(completionParameter: { message1 -> String in
        let t = type(of: message1)
        print(t)
        return message1
        })
    return dspmsg

The returned value for dspmsg is Void apparently, but when I check the contents of message1 inside the closure completionParameter for requestList, I always get the expected text, and that it is of type String. Before using that printer() function I tried to print the return from the closure directly, which led me to the same error.

My goal is to request website data and use it outside of the closure.

My suspicion is that the return in printer() happens before completionParameter has finished. But as I have stated, directly printing the return and circumventing the timing problem, prints an empty tuple, which as I understand is equal to Void.


Solution

  • You should take a look at Async/Await Concurrency in Swift. You can try something like:

    1. Create an async method and use URLSession async method data(from: URL)

    func requestList() async -> String {
        let url = URL(string: "https://www.google.de")!
        do {
            let (_, response) = try await URLSession.shared.data(from: url)
            guard let mime = response.mimeType else {
                throw URLError(.unknown)
            }
            return mime
        } catch {
           return error.localizedDescription
        }
    }
    

    1. Declare your printer method as async as well:

    func printer() async -> String {
        let dspmsg = await requestList()
        print(dspmsg)
        return dspmsg
    }
    
    1. Then you can call it using await

    Task {
        let string = await printer() // text/html
    }