1

I have a problem with the function that I created, I want to return multiple values but seems like, I keep getting this error

Unexpected non-void return value in void function

func calculateDistance(_ firstLat: Double, _ firstLong: Double, _ secondLat: Double, _ secondLong: Double) -> (Double, Double, String) {

        let URL = "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=\(firstLat),\(firstLong)&destinations=\(secondLat),\(secondLong)&key=KEYID"
        Alamofire.request(URL)
            .responseJSON { response in

                if let value = response.result.value {
                    let json = JSON(value)
                    let distance = json["rows"][0]["elements"][0]["distance"]["value"].double! / 1000 // Double
                    let price = distance * 1.0 // Double
                    let duration = json["rows"][0]["elements"][0]["duration"]["text"] // String
                    return (distance, price, duration) // Keep getting this error on this line
                }
        }


    }

What did I do wrong? I return the correct data type.

Christopher Oezbek
  • 23,994
  • 6
  • 61
  • 85
sinusGob
  • 4,053
  • 12
  • 46
  • 82
  • 1
    I think you need to use a completion handler. – koropok Aug 16 '17 at 07:52
  • Use completion handler, not return, also you are not returning anything on the current function, the `Alamorefire.request` dont return anything in the closure – Tj3n Aug 16 '17 at 07:57

3 Answers3

4

First mistake here is that Alamofire.request... is asynchronous. So you can't return a value fetched using that in your function.

The reason you are getting an error is because you are no longer in your function when you are trying to return. You are in the function that is the completion handler of the Alamofire request.

In order to get something out of this you will have to pass it into a completion handler of your own. Like this...

func calculateDistance(_ firstLat: Double, _ firstLong: Double, _ secondLat: Double, _ secondLong: Double, completionHandler: @escaping (Double, Double, String) -> ()) {

    let URL = "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=\(firstLat),\(firstLong)&destinations=\(secondLat),\(secondLong)&key=KEYID"
        Alamofire.request(URL).responseJSON { response in
            if let value = response.result.value {
                let json = JSON(value)
                let distance = json["rows"][0]["elements"][0]["distance"]["value"].double! / 1000 // Double
                let price = distance * 1.0 // Double
                let duration = json["rows"][0]["elements"][0]["duration"]["text"] // String
                completionHandler(distance, price, duration) // Keep getting this error on this line
            }
        }
    }
}

The signature (Double, Double, String) -> () is a function that takes in two Doubles and a String. When you get the data back from the network you are then calling this function.

Then you would call it like...

calculateDistance(1, 2, 3) { (distance, price, duration) in
    // do something with the distance price and duration
}

Just another note here... It is really bad practice to squash the parameter names in your function by using _. Do it (maybe) for the first parameter if it is obvious from the function name what it is but don't do it for the following parameters.

Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • Thanks for the answer, but I keep getting error `fatal error: unexpectedly found nil while unwrapping an Optional value` – sinusGob Aug 16 '17 at 08:39
  • I tried to print out the values and it shows the correct data. But when I use this completionHandler, it returns an error – sinusGob Aug 16 '17 at 08:39
  • @sinusGob unexpectedly found nil is a whole different problem not related to this question. There’s are many SO questions asking this. I’d recommend readin a book about Swift to learn the basics first. – Fogmeister Aug 16 '17 at 08:42
  • I got what you mean, but I run two separate functions, one with completion Handler and one without completion Handler, without completion handler returns the value correctly but when it comes to completionHandler it returns this error – sinusGob Aug 16 '17 at 08:44
  • @sinusGob unexpectedly found nil is a whole different problem not related to this question. There are many SO question asking this. I’d recommend reading a book about Swift to learn the basics first. – Fogmeister Aug 16 '17 at 08:45
  • Alright, thanks anyway. – sinusGob Aug 16 '17 at 08:46
  • @sinusGob Seriously. Go to google and type “unexpectedly found nil”. This question is about returning a value from a completion handler. Nothing to do with force unwrapping doubles from a dictionary. If you take literally 5 seconds to google it you will have an answer. – Fogmeister Aug 16 '17 at 08:48
  • Thanks again for the advice and detailed explanation of the answer, it really helps! – sinusGob Aug 16 '17 at 08:53
0

You need to use block to return values

func calculateDistance(_ firstLat: Double, _ firstLong: Double, _ secondLat: Double, _ secondLong: Double, completion: @escaping (Double, Double, String)->()) {

        let URL = "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=\(firstLat),\(firstLong)&destinations=\(secondLat),\(secondLong)&key=KEYID"
        Alamofire.request(URL)
            .responseJSON { response in

                if let value = response.result.value {
                    let json = JSON(value)
                    let distance = json["rows"][0]["elements"][0]["distance"]["value"].double! / 1000 // Double
                    let price = distance * 1.0 // Double
                    let duration = json["rows"][0]["elements"][0]["duration"]["text"] // String
                    completion(distance, price, duration) // return values
                }
        }


    }

To get that values use this:

//call the method
 calculateDistance(SomeDouble, SomeDouble, SomeDouble, SomeDouble) {(distance, price, duration) in
         //here you can use those values
    }
Woof
  • 1,207
  • 1
  • 11
  • 21
  • Also you can make your completion to be optional. It will allow you to handle an errors that you may have if something is wrong with connection or values received – Woof Aug 16 '17 at 08:00
0

The return statement is for the closure which is the callback of the Alamofire request and not the calculateDistance function. This closure is executed when the response of the request has been received. As the request is asynchronous, this closure is executed long after your function calculateDistance has returned.

Instead, you could use a delegate pattern or a completion handler.

func calculateDistance(_ firstLat: Double, _ firstLong: Double, _ secondLat: Double, _ secondLong: Double, completion: @escaping (Double, Double, String) -> ()) {
    Alamofire.request(...).responseJSON {
        parse response
        completion(distance, price, duration)
    }
}
Palle
  • 11,511
  • 2
  • 40
  • 61