How to download JSON from the internet and decode it into any Codable type 如何从 Internet 下载 JSON 并将其解码为任何 Codable 类型

How to download JSON from the internet and decode it into any Codable type 如何从 Internet 下载 JSON 并将其解码为任何 Codable 类型

温馨提示:本文最后更新于2025-02-10 11:30:27,某些文章具有时效性,若有错误或已失效,请在下方留言

Fetching JSON from the network and using Codable to convert it into native Swift objects is probably the most common task for any Swift developer, usually followed by displaying that data in a List or UITableView depending on whether they are using SwiftUI or UIKit.
从网络获取 JSON 并使用 Codable 将其转换为原生 Swift 对象可能是任何 Swift 开发人员最常见的任务,通常随后在 List 或 UITableView 中显示该数据,具体取决于他们使用的是 SwiftUI 还是 UIKit。

Well, using Swift’s concurrency features we can write a small but beautiful extension for URLSession that makes such work just a single line of code – you just tell iOS what data type to expect and the URL to fetch, and it will do the rest.
好吧,使用 Swift 的并发功能,我们可以为 URLSession 编写一个小而漂亮的扩展,它使这样的工作只需一行代码 – 您只需告诉 iOS 需要什么数据类型和要获取的 URL,剩下的工作就会交给它。

To add some extra flexibility, we can also provide options to customize decoding strategies for keys, data, and dates, providing sensible defaults for each one to keep our call sites clear for the most common usages.
为了增加一些额外的灵活性,我们还可以提供选项来自定义键、数据和日期的解码策略,为每个策略提供合理的默认值,以保持我们的调用站点对于最常见的用途清晰。

Here’s how it’s done:  这是如何完成的:

extension URLSession {
    func decode<T: Decodable>(
        _ type: T.Type = T.self,
        from url: URL,
        keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys,
        dataDecodingStrategy: JSONDecoder.DataDecodingStrategy = .deferredToData,
        dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate
    ) async throws  -> T {
        let (data, _) = try await data(from: url)

        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = keyDecodingStrategy
        decoder.dataDecodingStrategy = dataDecodingStrategy
        decoder.dateDecodingStrategy = dateDecodingStrategy

        let decoded = try decoder.decode(T.self, from: data)
        return decoded
    }
}

That does several things:
这有几件事:

  1. It’s an extension on URLSession, so you can go ahead and create your own custom session with a unique configuration if needed.
    它是 URLSession 的扩展,因此如果需要,您可以继续使用唯一配置创建自己的自定义会话。
  2. It uses generics, so that it will work with anything that conforms to the Decodable protocol – that’s half of Codable, so if you use Codable it will work there too.
    它使用泛型,因此它可以与任何符合 Decodable 协议的东西一起工作——这是 Codable 的一半,所以如果你使用 Codable,它也可以在那里工作。
  3. It uses T.self for the default data type, so if Swift can infer your type then you don’t need to repeat yourself.
    它使用 T.self 作为默认数据类型,因此如果 Swift 可以推断出您的类型,那么您就不需要重复自己。
  4. It allows all errors to propagate to your call site, so you can handle networking and/or decoding errors as needed.
    它允许所有错误传播到您的调用站点,因此您可以根据需要处理网络和/或解码错误。

To use the extension in your own code, first define a type you want to work with, then go ahead and call decode() in whichever way you need:
要在你自己的代码中使用扩展,首先定义你想要使用的类型,然后以你需要的任何方式调用 decode() :

extension URLSession {
    func decode<T: Decodable>(
        _ type: T.Type = T.self,
        from url: URL,
        keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys,
        dataDecodingStrategy: JSONDecoder.DataDecodingStrategy = .deferredToData,
        dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate
    ) async throws  -> T {
        let (data, _) = try await data(from: url)

        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = keyDecodingStrategy
        decoder.dataDecodingStrategy = dataDecodingStrategy
        decoder.dateDecodingStrategy = dateDecodingStrategy

        let decoded = try decoder.decode(T.self, from: data)
        return decoded
    }
}

struct User: Codable {
    let id: UUID
    let name: String
    let age: Int
}

struct Message: Codable {
    let id: Int
    let user: String
    let text: String
}

do {
    // Fetch and decode a specific type
    let url1 = URL(string: "https://hws.dev/user-24601.json")!
    let user = try await URLSession.shared.decode(User.self, from: url1)
    print("Downloaded \(user.name)")

    // Infer the type because Swift has a type annotation
    let url2 = URL(string: "https://hws.dev/inbox.json")!
    let messages: [Message] = try await URLSession.shared.decode(from: url2)
    print("Downloaded \(messages.count) messages")

    // Create a custom URLSession and decode a Double array from that
    let config = URLSessionConfiguration.default
    config.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData
    let session = URLSession(configuration: config)

    let url3 = URL(string: "https://hws.dev/readings.json")!
    let readings = try await session.decode([Double].self, from: url3)
    print("Downloaded \(readings.count) readings")
} catch {
    print("Download error: \(error.localizedDescription)")
}
下载图标
how-to-download-json-from-the-internet-and-decode-it-into-any-codable-type-1.zip
zip文件
51.8K

As you can see, with that small extension in place it becomes trivial to fetch and decode any type of Codable data with just one line of Swift.
正如你所看到的,有了这个小的扩展,只用一行 Swift 就可以很容易地获取和解码任何类型的 Codable 数据。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享