Swift:从 URL 加载 JSON 数据

Posted

技术标签:

【中文标题】Swift:从 URL 加载 JSON 数据【英文标题】:Swift: Loading JSON data from a URL 【发布时间】:2021-06-21 05:33:45 【问题描述】:

我正在尝试修改地标教程中的 Apple 代码,以从远程 URL 加载 JSON 数据。 url 是一个 php 脚本,它返回纯文本 JSON 数据。

苹果的代码:

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:\n\(error)")
    
    
    do 
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
     catch 
        fatalError("Couldn't parse \(filename) from main bundle:\n\(error)")
    

以及我当前修改的代码:

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)\n\(error)")
        
    

我得到的错误是Unexpected non-void return value in void function

我认为该函数应该返回一个 T 的实例。我哪里出错了?

【问题讨论】:

"我得到的错误是 Unexpected non-void return value in void function" Where!? 您的 URL 会话缺少某些内容。 这能回答你的问题吗? Unexpected Non-Void Return Value In Void Function (Swift 2.0) 我认为您需要一个完成块而不是返回。如果您使用新的 async-await,则 return 很好,但此代码不适用于此。 我同意@RajaKishan-如果你正在运行异步任务,你不应该使用 return,你的变量的值可能会被 loadRemoteJSON 初始化为 nil,因为 Swift 将继续前进通过您的代码,而无需等待该变量的初始化。 【参考方案1】:

您需要一个完成块而不是返回类型。您正在执行异步任务。 URLSession.shared.dataTask 是异步类型。

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)\n\(error)")
        
    

用法:

struct TestModel: Decodable 
    var name: String


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

如果您使用的是 Swift 5.5,那么您可以使用 Async Await 返回您的数据。网上有很多文章和视频。您可以查看this。

【讨论】:

【参考方案2】:
func loadRemoteJSON<T: Decodable>(_ urlString: String,completion: @escaping (T)->Void)

使用完成块很简单,只需解码 JSON 并将其传递给您的完成处理程序。

let decodedJSON = try decoder.decode(T.self, from: data)
completion(decodedJSON)

现在,当您调用 loadRemoteJSON 时,您将能够访问函数完成块内的 JSON,例如:

loadRemoteJSON(urlString: someString) data in
 //data is your returned value of the generic type T.

【讨论】:

以上是关于Swift:从 URL 加载 JSON 数据的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中将 JSON 加载到 UItableView

修改行数组时,Swift 2数据不会重新加载数据

如何在 Swift 中从同一站点重新加载新的 JSON 数据?

Swift 5:给定的数据不是有效的JSON(将数据从API加载到表格视图)

从 URL 加载带有 JSON 数据的 ListView

从网络URL加载并验证JSON数据