0

I have the two functions below that I am using to help parse JSON in Swift. The first function works beautifully with any JSON I toss at it.

The second method is giving me fits, though and I can't figure out the issue. I essentially want to do the same thing as the first function, but my data comes from a URLSession instead of a local file.

Any ideas what I'm doing wrong here? I get a bizarre compiler error that Unexpected non-void return value in void function but the signatures are exactly the same.

import Foundation
import SwiftUI


// Populates Model from local files
public func loadFromJson<T: Decodable>(_ filename: String) -> T {
    let data: Data
    
    guard let path = Bundle.main.path(forResource: filename, ofType: "json")
   
    else{
        fatalError("\(filename) not found.")
    }
    do {
        let file = URL(fileURLWithPath: path)
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Could not load \(filename): (error)")
    }
    
    do{
        return try JSONDecoder().decode(T.self, from: data)
    } catch {
        fatalError("Unable to parse \(filename): (error)")
    }
}

// Populates Model from REST endpoint
public func loadFromJsonFromURL<T: Decodable>(_ urlString: String) -> T {
    let data: Data
    
    let url = URL(string: urlString)!

    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        
        if let error = error {
            fatalError("Error: \(error.localizedDescription)")
        }
        
        
        guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
            fatalError("Error: invalid HTTP response code")
        }
        
        guard let data = data else {
            fatalError("Error: missing response data")
        }

        do {
            return try JSONDecoder().decode(T.self, from: data)
        }
        catch {
            print("Error: \(error.localizedDescription)")
        }
    }
    task.resume()
    
}
0

1 Answer 1

0

dataTask(with: completionHandler:) is an async method. So, till the time the completionHandler is called after receiving the response, the method loadFromJsonFromURL(_:_:) has already returned.

You need to use a closure to pass the data back after receiving the response from API.

public func loadFromJsonFromURL<T: Decodable>(_ urlString: String, _ handler: @escaping ((T?)->())) {
    if let url = URL(string: urlString) {
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error {
                fatalError("Error: \(error.localizedDescription)")
            }
            guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
                fatalError("Error: invalid HTTP response code")
            }
            guard let data = data else {
                fatalError("Error: missing response data")
            }
            do {
                let value = try JSONDecoder().decode(T.self, from: data)
                handler(value)
            }
            catch {
                print("Error: \(error.localizedDescription)")
                handler(nil)
            }
        }
        task.resume()
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.