用于 API 的 JSONDecoder 和文本视图结构中的数据的问题
Posted
技术标签:
【中文标题】用于 API 的 JSONDecoder 和文本视图结构中的数据的问题【英文标题】:Issues with JSONDecoder for API and Text a data in a View struct 【发布时间】:2021-03-30 13:30:45 【问题描述】:我是 SwiftUI 的初学者,我正在尝试为 ios 开发一个应用程序。
我正在尝试使用 API 请求中的数据在我的主视图结构中对它们进行文本处理,我将不同的 vstack、hstack 等放在其中...
为此,我遵循了本教程:https://www.youtube.com/watch?v=lFE-TJJxxLU
我的 API 响应是:https://api.ethermine.org/miner/b5404f020334f52b33012af3587e69305eabee2c/dashboard
所以我这样准备我的模型:
import Foundation
struct ethermineResponse: Decodable
var status : String
var data : dataDetails
struct dataDetails: Decodable
var statistics : [statistics]
var workers : [workers]
var currentStatistics : currentStatistics
var settings : settings
struct statistics: Decodable
var time : Date
var reportedHashrate : Double
var currentHashrate : Double
var validShares : Double
var invalidShares : Int
var staleShares : Int
var activeWorkers : Int
struct workers: Decodable
var worker : String
var time : Date
var lastSeen : Date
var reportedHashrate : Double
var currentHashrate : Double
var validShares : Double
var invalidShares : Int
var staleShares : Int
struct currentStatistics: Decodable
var time : Date
var lastSeen : Date
var reportedHashrate : Double
var currentHashrate : Double
var validShares : Double
var invalidShares : Double
var staleShares : Int
var activeWorkers : Int
var unpaid : Double
struct settings: Decodable
var monitor : Int
var minPayout : Double
var email : String
我编写了我的请求:
import Foundation
enum dataError: Error
case noDataAvailable
case canNotProcessData
struct ethermineRequest
let resourceURL:URL
init(wallet: String)
let resourceString = "https://api.ethermine.org/miner/\(wallet)/dashboard"
guard let resourceURL = URL(string: resourceString) else fatalError()
self.resourceURL = resourceURL
func getData(completionHandler: @escaping (Result<ethermineResponse, dataError>) -> Void)
let task = URLSession.shared.dataTask(with: resourceURL) data, _, _ in
guard let jsondata = data else
completionHandler(.failure(.noDataAvailable))
return
do
let ETHData = try JSONDecoder().decode(ethermineResponse.self, from: jsondata)
completionHandler(.success(ETHData))
catch
print("error")
task.resume()
在我的主视图结构中,我试图在 VStack 中以文本为例,例如我的“未付”值:
VStack
let API = ethermineRequest(wallet: wallet)
API.getData (ethermineResponse) in
Text(currentStatistics.unpaid!)
Spacer()
但我有这个错误:
var body: some View
“无法生成表达式诊断;请提交错误报告”
我如何发送我的 API 请求中的未付金额等文本?
谢谢:)
【问题讨论】:
不相关但print("error")
=> print("Error: \(error)")
,打印error
,它可能会提供信息!。
我试过了,现在我有更多细节:类型'currentStatistics.Type'不能符合'StringProtocol';只有结构/枚举/类类型可以符合协议并且类型“()”不能符合“视图”;只有结构/枚举/类类型可以符合协议
【参考方案1】:
大多数问题可能是因为您对对象的命名方式。
例如,
var statistics : [statistics]
var workers : [workers]
编译器如何区分你的变量和你的struct
这些更糟糕,因为您甚至没有数组来使它们不同。
var currentStatistics : currentStatistics
var settings : settings
请以大写字母开头的class
和struct
命名。
var statistics : [Statistics]
var settings : Settings
var currentStatistics : CurrentStatistics
有些教程是以其他方式教授的,但请注意所有来自 Apple 的 class
、struct
、protocol
,它们都不是以小写字母开头的 var
和 let
注意String
、Int
、Double
、Foundation
、ContentView
它们都以大写字母开头。
https://swift.org/documentation/api-design-guidelines/#fundamentals
这里的这条线也可能是一个问题。有几个原因。
let API = ethermineRequest(wallet: wallet)
API.getData (ethermineResponse) in
1st - 您正在body
中创建变量/发出请求。那项工作应该在class ViewModel
中,body
只是为了显示事物和触发动作而不做任何工作。
body
可以随时被许多触发器重新加载,每次重新加载时您都会执行该请求。
第二个 - unpaid
是一个 Double
,所以要显示它,你必须使用它。
Text(currentStatistics.unpaid!.description)
但是currentStatistics
变量应该在ViewModel
中,因为它正在显示,所以它没有被创建。
我将所有struct
切换为以大写字母开头。下面是一种方法,但有很多方法可以实现。看看cmets。
class EthermineViewModel: ObservableObject
@Published var wallet: String = ""
didSet
getResponse(wallet: wallet)
@Published var response: EthermineResponse?
private func getResponse(wallet: String)
let request = EthermineRequest(wallet: wallet)
request.getData (ethermineResponse) in
switch ethermineResponse
case .failure(let error):
//This should somehow trigger an Alert to let the user know there has been an error
print(error)
case .success(let response):
self.response = response
struct EthermineView: View
@StateObject var vm: EthermineViewModel = EthermineViewModel()
let wallet: String = "b5404f020334f52b33012af3587e69305eabee2c"
var body: some View
Text(vm.response?.data.currentStatistics.unpaid.description ?? "nil")
.onAppear()
vm.wallet = wallet
struct EthermineView_Previews: PreviewProvider
static var previews: some View
EthermineView()
struct EthermineRequest
let resourceURL:URL
init(wallet: String)
let resourceString = "https://api.ethermine.org/miner/\(wallet)/dashboard"
guard let resourceURL = URL(string: resourceString) else
fatalError("resourceString == invalid url")
self.resourceURL = resourceURL
func getData(completionHandler: @escaping (Result<EthermineResponse, DataError>) -> Void)
let task = URLSession.shared.dataTask(with: resourceURL) data, urlResponse, responseError in
guard let jsondata = data else
print(responseError ?? "responseError")
//Is the absence of data the only type of error you could have?
completionHandler(.failure(.noDataAvailable))
return
do
let data = try JSONDecoder().decode(EthermineResponse.self, from: jsondata)
completionHandler(.success(data))
catch
//this message will be much more useful
print(error)
//or
let nsError = error as NSError
print(nsError.localizedFailureReason ?? "no failure reason")
print(nsError.localizedRecoveryOptions ?? "no recovery options")
task.resume()
【讨论】:
你说的一切看起来都是真的,但是 OP 还试图在他的视图层次结构中间进行异步网络调用,这永远不会起作用。 谢谢我用你所说的更正了我的工作表,我的“var body”仍然出现错误“无法生成表达式诊断;请提交错误报告”。但现在更干净了:) 我同意我按照您的评论添加了这一点。 @DomTorreto 看看我添加的其余部分。将请求从View
中取出并放入class ViewModel : ObservableObject
中,只显示来自@Published var currentStatistics: CurrentStatistics
的数据
谢谢,但我不知道该怎么做API 并在不同的 vstack 和 hstack 中将其推送到我的视图以上是关于用于 API 的 JSONDecoder 和文本视图结构中的数据的问题的主要内容,如果未能解决你的问题,请参考以下文章
如何准备 API 响应以在 swift 中与 jsonDecoder 一起使用
Python 3 中的 JSONdecoder 错误。来自 API 的 Json