You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 11:25:35