【问题标题】:Swift: Loading JSON data from a URLSwift:从 URL 加载 JSON 数据
【发布时间】: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 会话缺少某些内容。
  • 我认为您需要一个完成块而不是返回。如果您使用新的 async-await,则 return 很好,但此代码不适用于此。
  • 我同意@RajaKishan-如果你正在运行异步任务,你不应该使用 return,你的变量的值可能会被 loadRemoteJSON 初始化为 nil,因为 Swift 将继续前进通过您的代码,而无需等待该变量的初始化。

标签: json 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.
    }
    

    【讨论】:

      猜你喜欢
      • 2016-07-14
      • 2016-12-28
      • 2014-09-20
      • 1970-01-01
      • 2017-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-14
      相关资源
      最近更新 更多