Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am attempting to modify Apple's code from the Landmarks tutorial to load JSON data from a remote URL. The url is a php script which returns plaintext JSON data.

Apple's code:

func loadLocalJSON<T: Decodable>(_ filename: String) -> T {
    let data: Data
    
    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
        else {
            fatalError("Couldn't find (filename) in main bundle")
    }
    
    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't load (filename) from main bundle:
(error)")
    }
    
    do {
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse (filename) from main bundle:
(error)")
    }
}

And my code as currently modified:

func loadRemoteJSON<T: Decodable>(_ urlString: String) -> T {
    let data: Data
    
    guard let url = URL(string: urlString) else {
        fatalError("Invalid URL")
    }
    
    let request = URLRequest(url: url)
    URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data else {
            fatalError(error?.localizedDescription ?? "Unknown Error")
        }
        
        do {
            let decoder = JSONDecoder()
            return try decoder.decode(T.self, from: data) // <--ERROR HERE
        } catch {
            fatalError("Couldn't parse data from (urlString)
(error)")
        }
    }
}

The error I am getting is Unexpected non-void return value in void function

I thought the function was supposed to be returning an instance of T. Where am I going wrong?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
195 views
Welcome To Ask or Share your Answers For Others

1 Answer

You need a completion block instead of a return type. You are doing the async task. URLSession.shared.dataTask is async type.

func loadRemoteJSON<T: Decodable>(_ urlString: String, completion: @escaping  ((T) -> Void)) {
    let data: Data
    
    guard let url = URL(string: urlString) else {
        fatalError("Invalid URL")
    }
    
    let request = URLRequest(url: url)
    URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data else {
            fatalError(error?.localizedDescription ?? "Unknown Error")
        }
        
        do {
            let decoder = JSONDecoder()
            let data = try decoder.decode(T.self, from: data)
            completion(data)
        } catch {
            fatalError("Couldn't parse data from (urlString)
(error)")
        }
    }
}

Usage:

struct TestModel: Decodable {
    var name: String
}

loadRemoteJSON("urlstring") { (data: TestModel) in
    print(data.name)
}

If you are using Swift 5.5 then you can return your data by using Async Await. There many articles and videos are available on the net. You can check this.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...