Currently I am decoding a JSON response from an API and storing it into a struct "IPGeolocation". I want to be able to store this data in a variable or return an instance of this struct such that I can access the values in views.
Struct:
struct IPGeolocation: Decodable {
var location: Coordinates
var date: String
var sunrise: String
var sunset: String
var moonrise: String
var moonset: String
}
struct Coordinates: Decodable{
var latitude: Double
var longitude: Double
}
URL extension with function getResult:
extension URL {
func getResult<T: Decodable>(completion: @escaping (Result<T, Error>) -> Void) {
URLSession.shared.dataTask(with: self) { data, response, error in
guard let data = data, error == nil else {
completion(.failure(error!))
return
}
do {
completion(.success(try data.decodedObject()))
} catch {
completion(.failure(error))
}
}.resume()
}
}
Function that retrieves and decodes the data:
func getMoonTimes(lat: Double, long: Double) -> Void{
urlComponents.queryItems = queryItems
let url = urlComponents.url!
url.getResult { (result: Result<IPGeolocation, Error>) in
switch result {
case let .success(result):
print("Printing returned results")
print(result)
case let .failure(error):
print(error)
}
}
}
My goal is to take the decoded information and assign it to my struct to be used in views after. The results variable is already an IPGeolocation struct once the function runs. My question lies in the best way to store it or even return it if necessary.
Would it make sense to have getResult return an IPGeolocation? Are there better/different ways?
Thanks!
EDIT: I made changes thanks to help from below comments from Leo Dabus.
func getMoonTimes(completion: @escaping (IPGeolocation?,Error?) -> Void) {
print("STARTING FUNC")
let locationViewModel = LocationViewModel()
let apiKey = "AKEY"
let latitudeString:String = String(locationViewModel.userLatitude)
let longitudeString:String = String(locationViewModel.userLongitude)
var urlComponents = URLComponents(string: "https://api.ipgeolocation.io/astronomy?")!
let queryItems = [URLQueryItem(name: "apiKey", value: apiKey),
URLQueryItem(name: "lat", value: latitudeString),
URLQueryItem(name: "long", value: longitudeString)]
urlComponents.queryItems = queryItems
urlComponents.url?.getResult { (result: Result<IPGeolocation, Error>) in
switch result {
case let .success(geolocation):
completion(geolocation, nil)
case let .failure(error):
completion(nil, error)
}
}
}
To call this method from my view:
struct MoonPhaseView: View {
getMoonTimes(){geolocation, error in
guard let geolocation = geolocation else {
print("error:", error ?? "nil")
return
}
}
...
...
...