Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift return data from URLSession

I cannot return data from my HTTPrequest and I can't get completion handlers to work either. So please assist me in my quest to solve this issue:

public static func createRequest(qMes: message, location: String, method: String) -> String{
    let requestURL = URL(string: location)
    var request = URLRequest(url: requestURL!)

    request.httpMethod = method
    request.httpBody = qMes.toString().data(using: .utf8)

    let requestTask = URLSession.shared.dataTask(with: request) {
        (data: Data?, response: URLResponse?, error: Error?) in

        if(error != nil) {
            print("Error: \(error)")
        }

        return String(data: data!, encoding: String.Encoding.utf8) as String!
    }
    requestTask.resume()
}

It is excpecting non-void return statement in void function. At this point I'm clueless...

like image 286
Bram Avatar asked Mar 27 '17 13:03

Bram


4 Answers

You can use this completion block method to send the final response:

For Instance: I have returned String in completion block, after successful response without error just pass the result in block.

  public func createRequest(qMes: String, location: String, method: String , completionBlock: @escaping (String) -> Void) -> Void
    {

        let requestURL = URL(string: location)
        var request = URLRequest(url: requestURL!)

        request.httpMethod = method
        request.httpBody = qMes.data(using: .utf8)

        let requestTask = URLSession.shared.dataTask(with: request) {
            (data: Data?, response: URLResponse?, error: Error?) in

            if(error != nil) {
                print("Error: \(error)")
            }else
            {

                let outputStr  = String(data: data!, encoding: String.Encoding.utf8) as String!
                //send this block to required place
                completionBlock(outputStr!);
            }
        }
        requestTask.resume()
    } 

You can use this below code to execute the above completion block function:

 self.createRequest(qMes: "", location: "", method: "") { (output) in

        }

This will solve your following requirement.

like image 162
Abilash Balasubramanian Avatar answered Nov 06 '22 14:11

Abilash Balasubramanian


{
    (data: Data?, response: URLResponse?, error: Error?) in

    if(error != nil) {
        print("Error: \(error)")
    }

    return String(data: data!, encoding: String.Encoding.utf8) as String!
}

This part of your code is the completion handler for the dataTask() method. It's a block of code that you pass into the dataTask() method to be executed later on (when the server sends back some data or there's an error). It's not executed straight away.

This means that when your createRequest() method above is executing, it passes straight over that code, then onto the requestTask.resume() line, and then the method ends. At that point, because your method is defined as returning a String, you need to return a String. Returning it from the completion handler is no good because that hasn't been executed yet, that is going to be executed later on.

There's lots of different ways to handle asynchronous programming, but one way of tackling this is to change your createRequest() method so that it isn't defined to return a String, create a method that takes a String as a parameter which does whatever you wanted to do with the return value, and then call that method from your completion handler.

like image 6
Jim Avatar answered Nov 06 '22 13:11

Jim


Instead of using return, try using completion handlers as you mentioned in your question.

func createRequest(qMes: message, location: String, method: String, completionHandler: @escaping (_ data:Data?, _ response: URLResponse?, _ error: NSError?) -> Void)

Then instead of return you should use something like completionHandler(data, response, error)

And this is how you make the request:

var request = URLRequest(url: Foundation.URL(string: URL)!)
        request.httpMethod = method
        //request.addValue(authString, forHTTPHeaderField: "Authorization") // if you need some

        let task = URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in

            guard error == nil && data != nil else
            {
                print("error=\(error)")
                completionHandler(data, response, error as NSError?)
                return
            }

            completionHandler(data, response, error as NSError?)
        }) 

        task.resume()
like image 1
Slavcho Avatar answered Nov 06 '22 13:11

Slavcho


Just in your function call

var webString = try String(contentsOf: URL(string: url)!)

And you have full response in string, that you can return

like image 1
Vadim Avatar answered Nov 06 '22 14:11

Vadim