Swift 按下按钮时,API请求未在模拟器上显示
我正试图通过API请求从网站获取股票数据。在这个例子中,我想通过按下按钮来提取股票的符号。代码本身没有错误,但我不显示API请求,也不向模拟器提供符号。你知道我做错了什么吗Swift 按下按钮时,API请求未在模拟器上显示,swift,api,swiftui,Swift,Api,Swiftui,我正试图通过API请求从网站获取股票数据。在这个例子中,我想通过按下按钮来提取股票的符号。代码本身没有错误,但我不显示API请求,也不向模拟器提供符号。你知道我做错了什么吗 struct助手:视图{ @国家私有变量quoteData:quoteData? var body:一些观点{ HStack{ 垫片() VStack(对齐:。前导){ 文本(引用数据?.symbol??“) 按钮(操作:loadData){ 文本(“按此处”) } } } .onAppear(执行:loadData) }
struct助手:视图{
@国家私有变量quoteData:quoteData?
var body:一些观点{
HStack{
垫片()
VStack(对齐:。前导){
文本(引用数据?.symbol??“)
按钮(操作:loadData){
文本(“按此处”)
}
}
}
.onAppear(执行:loadData)
}
私有函数loadData(){
guard let url=url(字符串:https://financialmodelingprep.com/api/v3/quote/AAPL?apikey=836129f3de1b99ff975e910a4541254d)其他{
返回
}
URLSession.shared.dataTask(with:url){data,response,guard let data=data else中的错误{return}
如果让decodedata=try?JSONDecoder().decode(QuoteData.self,from:data){
DispatchQueue.main.async{
self.quoteData=decodedData
}
}
}1.简历()
}
}
在这里,我只是尝试从string类型的股票中获取符号。API地址没有id。
结构QuoteData:可解码{
变量符号:字符串?
}
结构帮助器\u预览:PreviewProvider{
静态var预览:一些视图{
助手()
}
}
我重构了一些东西:
struct ContentView: View {
@ObservedObject var loader = Loader()
var body: some View {
HStack {
Spacer()
VStack(alignment: .leading) {
Text(loader.quoteData?.symbol ?? ".")
Button(action: loader.loadData) {
Text("Press here")
}
}
}
}
}
class Loader : ObservableObject {
@Published var quoteData: QuoteData?
func loadData() {
guard let url = URL(string: "https://financialmodelingprep.com/api/v3/quote/AAPL?apikey=836129f3de1b99ff975e910a4541254d") else {
return
}
URLSession.shared.dataTask(with: url) { data, response, error in guard let data = data else { return }
do {
let decodedData = try JSONDecoder().decode([QuoteData].self, from: data)
DispatchQueue.main.async {
self.quoteData = decodedData.first
}
} catch {
print("Error: \(error)")
}
}.resume()
}
}
struct QuoteData: Decodable {
var symbol: String?
}
说明:
最基本的问题是API端点返回的是数组,而不是字典。因此,我将您的解码方法改为[QuoteData]
,而不是QuoteData
第二,由于您使用的是try?
,所以它会无声地失败。相反,我使用了do{}catch{}
,这样您就可以实际捕获并处理错误,而不是无声的失败
第三(这是可选的),我将数据加载移动到了一个ObservieObject,而不是在视图本身中进行工作,从而分离了它们的责任。我将向您介绍这一部分,以获得更详细的描述。我完全承认,在设计这个答案时,我偷了@nicksarno的作品。请阅读完整的答案,因为他和我对此问题给出了相当彻底的回答。我本来会把你介绍到那里的,但是这里还有很多东西需要解开 首先,请确保您更改了API密钥。您不应该发布私有API密钥。您为访问该数据付费(或将付费) 我想知道答案。您的请求代码不正确。我发布的是一个使用Combine的现代请求,在我发布的答案链接中进行了充分讨论。此外,我通过简单地运行
QuickType
(答案中也有引用)来更正您的解码器
解析JSON是一件痛苦的事,如果没有别的,那就从Quicktype
或其他解析器开始。在本例中,JSON数据是一个数组,即使您只请求了一个股票。解码器必须完全匹配JSON的结构,尽管它不需要JSON的每个元素。它还必须符合Codable
协议
import SwiftUI
struct Helper: View {
@State private var symbol: String?
var body: some View {
HStack {
Spacer()
VStack(alignment: .leading) {
Text(symbol ?? ".")
Button(action: { loadData() }) {
Text("Press here")
}
}
}
}
private func loadData() {
guard let url = URL(string: "https://financialmodelingprep.com/api/v3/quote/AAPL?apikey=836129f3de1b99ff975e910a4541254d") else {
return
}
URLSession.shared.dataTaskPublisher(for: url)
// fetch on background thread
.subscribe(on: DispatchQueue.global(qos: .background))
// recieve response on main thread
.receive(on: DispatchQueue.main)
// ensure there is data
.tryMap { (data, response) in
guard
let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return data
}
// decode JSON data to QuoteDecoder
.decode(type: QuoteDecoder.self, decoder: JSONDecoder())
// Handle results
.sink { (result) in
// will return success or failure
print("completion: \(result)")
} receiveValue: { (value) in
// if success, will return QuoteDecoder
// here you can update your view
print("value: \(value)")
// you can handle your data however you need to. Remember that it is an array of QuoteData.
if let quote = value.first {
self.symbol = quote.symbol
}
}
// After recieving response, the URLSession is no longer needed & we can cancel the publisher
.cancel()
}
}
struct QuoteData: Codable {
let symbol, name: String?
let price, changesPercentage, change, dayLow: Double?
let dayHigh, yearHigh, yearLow: Double?
let marketCap: Int?
let priceAvg50, priceAvg200: Double?
let volume, avgVolume: Int?
let exchange: String?
let quoteDatumOpen, previousClose, eps, pe: Double?
let earningsAnnouncement: String?
let sharesOutstanding, timestamp: Int?
enum CodingKeys: String, CodingKey {
case symbol, name, price, changesPercentage, change, dayLow, dayHigh, yearHigh, yearLow, marketCap, priceAvg50, priceAvg200, volume, avgVolume, exchange
case quoteDatumOpen = "open"
case previousClose, eps, pe, earningsAnnouncement, sharesOutstanding, timestamp
}
}
typealias QuoteDecoder = [QuoteData]
struct Helper_Previews: PreviewProvider {
static var previews: some View {
Helper()
}
}
谢谢大家给我这些有用的建议。我会实施的,非常感谢!如果你觉得这是可行的,请接受它作为答案。