-1

How do I return a double variable from a function?

class Api {
    func getCoordinates(latitude: Bool) -> Double {
        if (latitude) {
            let url = URL(string: "https://waterservices.usgs.gov/nwis/iv/?format=json&indent=on&sites=08155200&parameterCd=00065&siteStatus=all")!
            URLSession.shared.dataTask(with: url) { data, _, _ in
                if let data = data {
                    let posts = try! JSONDecoder().decode(Post.self, from: data)
                    let lat = (posts.value?.timeSeries?.first?.sourceInfo?.geoLocation?.geogLocation?.latitude)
                    return lat
                }
            }
            print(5)
//            return 5
        } else {
            print(3)
            return 3
        }
    }
}

Using this code returns:

Unexpected non-void return value in void function

I could always remove return lat but that would kind of defeat the purpose.

  • 1
    See other topics where they use `URLSession`. – El Tomato Jun 09 '21 at 02:16
  • You cannot _return_ anything from a function that gets its value asynchronously (unless you want to adopt the wonderful new `async` `await`). To do that, you would need to make time run backwards. – matt Jun 09 '21 at 03:14

1 Answers1

0

It's a closure. Async/await is coming very soon, but in the meantime, remember that URLSession.shared.dataTask is an async function. That means the completion handler/closure will be called at a later time.

So, instead of return, you'll need to add another completion handler.

class Api {
                                        /// add completion handler
    func getCoordinates(latitude: Bool, completion: @escaping ((Double) -> Void)) {
        if (latitude) {
            let url = URL(string: "https://waterservices.usgs.gov/nwis/iv/?format=json&indent=on&sites=08155200&parameterCd=00065&siteStatus=all")!
            URLSession.shared.dataTask(with: url) { data, _, _ in
                if let data = data {
                    let posts = try! JSONDecoder().decode(Post.self, from: data)
                    let lat = (posts.value?.timeSeries?.first?.sourceInfo?.geoLocation?.geogLocation?.latitude)
                    completion(lat) /// similar to `return lat`
                }
            }
            print(5)
        } else {
            print(3)
            completion(3) /// similar to `return 3`
        }
    }
}

Your old code probably looked something like this:

let returnedDouble = Api().getCoordinates(latitude: true)
print(returnedDouble)

Now, replace it with this:

Api().getCoordinates(latitude: true) { returnedDouble in
    print(returnedDouble)
}
aheze
  • 24,434
  • 8
  • 68
  • 125
  • 1
    Maybe this is a dumb question but what would I put in `...`? – Colin Miller Jun 09 '21 at 02:40
  • @ColinMiller edited my answer – aheze Jun 09 '21 at 02:43
  • 1
    "Async/await is coming very soon" You mean like yesterday? :) – matt Jun 09 '21 at 04:07
  • @matt (: in my defense, Xcode 13 is still in beta and not available to everyone – aheze Jun 09 '21 at 04:08
  • Yes, it's unclear to me what we're even allowed to say. – matt Jun 09 '21 at 04:15
  • What would I use for a completion handler? – Colin Miller Jun 11 '21 at 17:11
  • @ColinMiller what do you mean? – aheze Jun 11 '21 at 17:21
  • Would I just leave it as is with `@escaping` or do something else? – Colin Miller Jun 11 '21 at 17:40
  • @ColinMiller yeah, leave it as is. – aheze Jun 11 '21 at 18:01
  • Using `Api().getCoordinates(latitude: true) { returnedDouble in print(returnedDouble) }` gives me the errors `Contextual closure type '() -> Double' expects 0 arguments, but 1 was used in closure body` and `Cannot convert value of type '()' to closure result type 'Double'` – Colin Miller Jun 11 '21 at 20:01
  • @ColinMiller my bad. I mixed up the closure. Will edit my answer. – aheze Jun 11 '21 at 20:14
  • hmmm. I don't get any errors now but when I call the function with `struct HomeView: View { var body: some View{ Text("Hello") .onAppear() { Api().getCoordinates(latitude: true) { returnedDouble in print(returnedDouble) let x = returnedDouble print(x) } } } }` it doesn't seem to return/print anything. – Colin Miller Jun 11 '21 at 21:59
  • @ColinMiller then `if let data = data {` is most likely failing (data is nil). – aheze Jun 11 '21 at 22:02
  • I thought so too but when I ran it with this `if (latitude) { let url = URL(string: "https://waterservices.usgs.gov/nwis/iv/?format=json&indent=on&sites=08155200&parameterCd=00065&siteStatus=all")! print(url) URLSession.shared.dataTask(with: url) { data, _, _ in print(5) } }` it didn't print 5 as I requested because it was in the URLsession bit. How do I fix this? – Colin Miller Jun 11 '21 at 23:14
  • @ColinMiller maybe ask another question - this shouldn't be related to the `Unexpected non-void return value in void function` error – aheze Jun 13 '21 at 16:26