从 SwiftUI 中的 URL 获取 JSON
Posted
技术标签:
【中文标题】从 SwiftUI 中的 URL 获取 JSON【英文标题】:Fetching JSON from URL in SwiftUI 【发布时间】:2020-07-21 16:13:34 【问题描述】:以下是我要开始工作的代码,我要做的就是显示当前价格和它所在的货币。
链接返回格式为:
"currency":"USD","rate":"178.0466666666667"
import SwiftUI
import Combine
struct BitcoinPrice: Decodable, Identifiable
var id = UUID()
let currency: String
let rate: String
struct BSVPrice: View
@State private var requests = Set<AnyCancellable>()
@State private var exchangeRate = [BitcoinPrice]()
var body: some View
NavigationView
List(exchangeRate) rate in
VStack(alignment: .leading)
Text(rate.currency)
Text(rate.rate)
.navigationTitle("Bitcoin Price")
.onAppear
let bitcoinPriceURL = URL(string: "https://api.whatsonchain.com/v1/bsv/main/exchangerate")!
//let bitcoinPriceTask = fetch(bitcoinPriceURL, defaultValue: [BitcoinPrice]() )
fetch(bitcoinPriceURL, defaultValue: [BitcoinPrice]() )
exchangeRate = $0
func fetch<T: Decodable>(_ url: URL, defaultValue: T, completion: @escaping (T) -> Void)
let decoder = JSONDecoder()
URLSession.shared.dataTaskPublisher(for: url)
.retry(1)
.map(\.data)
.decode(type: T.self, decoder: decoder)
.replaceError(with: defaultValue)
.receive(on: DispatchQueue.main)
.sink(receiveValue: completion)
.store(in: &requests)
func fetch<T: Decodable>(_ url: URL, defaultValue: T) -> AnyPublisher<T, Never>
let decoder = JSONDecoder()
return URLSession.shared.dataTaskPublisher(for: url)
.retry(1)
.map(\.data)
.decode(type: T.self, decoder: decoder)
.replaceError(with: defaultValue)
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
struct BSVPrice_Previews: PreviewProvider
static var previews: some View
BSVPrice()
有谁知道为什么 JSON 没有加载到应用程序中?任何帮助都会很棒,我已经让代码与不同的 API 一起工作,所以有点困惑。
【问题讨论】:
您应该以某种方式获取并打印解码错误。有一个错误。 【参考方案1】:首先,您通过使用.replaceError(with: defaultValue)
来抑制错误,这将隐藏所有错误并将其替换为默认值(此处为空列表)。
在
func fetch<T: Decodable>(_ url: URL, defaultValue: T, completion: @escaping (T) -> Void)
你正在尝试解码T.self
:
.decode(type: T.self, decoder: decoder)
应该是BitcoinPrice
类型才能工作。
请注意,来自您的链接的响应是一个单个对象,而不是一个数组。
但是,在您看来,您将 [BitcoinPrice]
作为默认值传递:
fetch(bitcoinPriceURL, defaultValue: [BitcoinPrice]() ) ...
推断T
的类型为[BitcoinPrice]
。
同时从BitcoinPrice
中删除var id = UUID()
:
struct BitcoinPrice: Decodable
let currency: String
let rate: String
并像这样使用它:
List(exchangeRate, id: \.currency) rate in
我还建议对集合使用 复数 名称,即。 exchangeRates
而不是 exchangeRate
。
【讨论】:
感谢您的帮助!与 T.self 我试图使代码通用,以便它可以与任何东西一起使用,你是说我应该用 BitcoinPrice 替换 T.self 吗?我试图将您的建议合并到我的代码中,但它说我缺少一些参数` @HenryHudson 你的代码是通用的没有问题。但是如果你想解码BitcoinPrice
,你需要让你的泛型函数正确推断T
类型。您可以通过传递一些 BitcoinPrice
变量作为默认值来做到这一点。
我明白了,我现在添加了 BitcoinPrice() 的 defaultValue,但我仍然遇到一些错误,认为主要是它说我缺少来自 @State private var exchangeRates = BitcoinPrice 的参数(),它需要大括号中的 from 参数我试图将代码发布到此评论中,但受到 cmets 允许的字符数的限制
@HenryHudson exchangeRate
是一个数组。当您分配解码值时:exchangeRate = $0
将其替换为exchangeRate = [$0]
以上是关于从 SwiftUI 中的 URL 获取 JSON的主要内容,如果未能解决你的问题,请参考以下文章
如何从 SwiftUI 中的 Bundle 中的有效路径或 URL 将图像加载到 Image()?