Swift中如何存储非数组结构的API返回JSON数据以供视图调用?
如何存储非数组结构的API JSON响应以便在视图中使用?
我正在解码某API的JSON响应,通常会将结果存入数组以便后续在视图中访问,但当前使用的API返回的结果并非数组结构。请问如何存储这些JSON数据,以便在视图中使用?
我的数据获取函数
func loadStats(name: String) { guard let url = URL(string: "https://leetcode-stats-api.herokuapp.com/\(name)") else{return} URLSession.shared.dataTask(with: url) {(data, resp, err) in guard let data = data else {return} do { let res = try JSONDecoder().decode(Stats.self, from: data) DispatchQueue.main.async { //需要将'res'存储到某个地方 } }catch{ print("解码失败: \(error)") } }.resume() }
API返回的JSON响应
{ "status": "success", "message": "retrieved", "totalSolved": 121, "totalQuestions": 2463, "easySolved": 73, "totalEasy": 604, "mediumSolved": 45, "totalMedium": 1314, "hardSolved": 3, "totalHard": 545, "acceptanceRate": 56.63, "ranking": 461292, "contributionPoints": 222, "reputation": 0, "submissionCalendar": {} }
我的结构体定义
import Foundation struct Stats: Codable, Identifiable{ let id = UUID() let status: String let message: String let totalSolved: Int let totalQuestions: Int let easySolved: Int let totalEasy: Int let mediumSolved: Int let totalMedium: Int let hardSolved: Int let totalHard: Int let acceptanceRate: Double let ranking: Int let contributionPoints: Int let reputation: Int }
解决方案
因为API返回的是单个对象而非数组,直接用单个变量存储即可,根据你使用的开发场景,有几种实用的存储方式:
1. SwiftUI单视图场景:用@State变量
在SwiftUI视图里定义一个可选的Stats类型@State变量,解码成功后直接赋值:
// 视图结构体内部定义 @State private var userStats: Stats? // 在loadStats的主队列闭包中赋值 DispatchQueue.main.async { self.userStats = res }
之后在视图中安全访问并展示数据:
if let stats = userStats { Text("已解决题目总数: \(stats.totalSolved)") Text("简单题完成率: \(stats.easySolved)/\(stats.totalEasy)") // 其他数据展示逻辑 } else { ProgressView("加载中...") }
2. 跨视图共享数据:用ObservableObject
如果需要在多个视图间共享统计数据,创建一个ObservableObject类管理数据:
import SwiftUI class StatsViewModel: ObservableObject { @Published var userStats: Stats? func loadStats(name: String) { guard let url = URL(string: "https://leetcode-stats-api.herokuapp.com/\(name)") else{return} URLSession.shared.dataTask(with: url) {(data, resp, err) in guard let data = data else {return} do { let res = try JSONDecoder().decode(Stats.self, from: data) DispatchQueue.main.async { self.userStats = res } }catch{ print("解码失败: \(error)") } }.resume() } }
然后在视图中通过@StateObject引用这个ViewModel:
struct StatsView: View { @StateObject private var viewModel = StatsViewModel() var body: some View { VStack { Button("加载数据") { viewModel.loadStats(name: "你的LeetCode用户名") } if let stats = viewModel.userStats { Text("当前排名: \(stats.ranking)") Text("整体通过率: \(stats.acceptanceRate)%") } else { Text("点击按钮加载数据") } } } }
3. UIKit场景:用普通属性+UI刷新
在UIKit的ViewController中定义可选Stats属性,赋值后手动刷新UI:
class ViewController: UIViewController { private var userStats: Stats? @IBOutlet weak var totalSolvedLabel: UILabel! func fetchStats() { loadStats(name: "你的用户名") } func loadStats(name: String) { guard let url = URL(string: "https://leetcode-stats-api.herokuapp.com/\(name)") else{return} URLSession.shared.dataTask(with: url) {(data, resp, err) in guard let data = data else {return} do { let res = try JSONDecoder().decode(Stats.self, from: data) DispatchQueue.main.async { self.userStats = res self.updateUI() } }catch{ print("解码失败: \(error)") } }.resume() } private func updateUI() { guard let stats = userStats else { return } totalSolvedLabel.text = "已解决题目: \(stats.totalSolved)" // 更新其他UI控件内容 } }
内容的提问来源于stack exchange,提问作者88Camino
相关产品推荐
相关产品推荐

