无法显示 API 的结果

问题描述 投票:0回答:1

代码本质上应该允许用户输入用户名、获取相关统计数据并将其显示在 UI 中。终端数据显示通过打印 JSON 已成功检索 API。

上下文:该 API 来自一款名为 Beyond All Reason 的游戏。

主要问题是我无法获取代码来解释结果并显示搜索到的用户玩过多少游戏,或与此相关的任何其他统计数据。正如你所看到的,我尝试在我的代码中实现 winCount。

import SwiftUI

struct User: Codable {
    let id: Int
    let username: String
}

struct UserStatsView: View {
    @State private var searchText: String = ""
    @StateObject private var viewModel = UserStatsViewModel()

    var body: some View {
        VStack {
            TextField("Enter username", text: $searchText)
                .padding()
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .autocapitalization(.none)

            Button(action: {
                Task {
                    await viewModel.loadStats(for: searchText)
                }
            }) {
                Text("Load Stats")
            }
            .padding()

            if viewModel.isLoading {
                ProgressView("Loading Stats...")
            } else if viewModel.dataReceived {
                Text("Data Received!")
                if let totalGames = viewModel.totalGames {
                    Text("Total Games: \(totalGames)")
                } else {
                    Text("Total Games: N/A")
                }
                if let winsCount = viewModel.winsCount {
                    Text("Number of Wins: \(winsCount)")
                } else {
                    Text("Number of Wins: N/A")
                }
            }
        }
        .padding()
    }
}

@MainActor
class UserStatsViewModel: ObservableObject {
    @Published var isLoading: Bool = false
    @Published var dataReceived: Bool = false
    @Published var totalGames: Int?
    @Published var winsCount: Int?
    
    @MainActor
    func loadStats(for username: String) async {
        isLoading = true
        dataReceived = false
        
        guard let url = URL(string: "https://api.bar-rts.com/cached-users") else {
            // Handle invalid URL
            return
        }
        
        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            
            let usersList = try JSONDecoder().decode([User].self, from: data)
            if let user = usersList.first(where: { $0.username == username }) {
                let userId = user.id
                await fetchMatches(for: userId, username: username)
            }
        } catch {
            print("Error: \(error)")
            // Handle error
        }
    }

    @MainActor
    private func fetchMatches(for userId: Int, username: String) async {
        guard var urlComponents = URLComponents(string: "https://api.bar-rts.com/replays") else {
            // Handle invalid URL
            return
        }
        
        let queryItems = [
            URLQueryItem(name: "page", value: "1"),
            URLQueryItem(name: "hasBots", value: "false"),
            URLQueryItem(name: "endedNormally", value: "true"),
            URLQueryItem(name: "preset", value: "team"),
            URLQueryItem(name: "players", value: username),
            URLQueryItem(name: "date", value: "2020-01-01"),
            URLQueryItem(name: "date", value: "2024-06-30")
        ]
        
        urlComponents.queryItems = queryItems
        
        guard let url = urlComponents.url else {
            // Handle invalid URL
            return
        }
        
        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            
            // Print the JSON data received
            if let jsonString = String(data: data, encoding: .utf8) {
                print("Received JSON data: \(jsonString)")
            }
            
            // Decode the JSON data as usual
            let response = try JSONDecoder().decode(MatchDataResponse.self, from: data)
            let matches = response.data
            
            self.totalGames = matches.count
            self.winsCount = matches.filter { $0.allyTeams.contains { $0.winningTeam } }.count
            self.isLoading = false
            self.dataReceived = true
        } catch {
            print("Error: \(error)")
            // Handle error
        }
    }
}


import Foundation

// Structures for representing the JSON data

// Top-level structure representing the entire JSON data
struct MatchDataResponse: Codable {
    let totalResults: Int
    let page: Int
    let limit: Int
    let data: [MatchData]
}

struct MatchData: Codable {
    let id: String
    let startTime: Date
    let durationMs: Double // Ensure this property is defined as Double
    let map: Map
    let allyTeams: [AllyTeam]
    
    private enum CodingKeys: String, CodingKey {
        case id, startTime, durationMs, map = "Map", allyTeams = "AllyTeams"
    }
}

// Structure representing the map information
struct Map: Codable {
    let fileName: String
    let scriptName: String
}

// Structure representing ally team data
struct AllyTeam: Codable {
    let winningTeam: Bool
    let players: [Player]
    let AIs: [AI] // Assuming there could be AI players
    
    private enum CodingKeys: String, CodingKey {
        case winningTeam, players = "Players", AIs
    }
}

// Structure representing player data
struct Player: Codable {
    let name: String
}

// Structure representing AI player data
struct AI: Codable {
    // AI properties if any, not available in the provided JSON snippet
}

struct ContentView: View {
    var body: some View {
        UserStatsView()
    }
}
swift xcode swiftui
1个回答
0
投票

有一个

DecodingError

错误:typeMismatch(Swift.Double,Swift.DecodingError.Context(codingPath:[CodingKeys(stringValue:“数据”,intValue:nil),_JSONKey(stringValue:“索引0”,intValue:0),CodingKeys(stringValue:“ startTime", intValue: nil)], debugDescription: "预期解码 Double 但发现了一个字符串。",underlyingError: nil))

startTime
是表示 ISO8601 日期的字符串。解码后的
Date
的默认 JSON 类型是
Double
,一个 UNIX 时间戳,这就是错误消息的内容。

startTime
解码为
String
或应用自定义日期解码策略。不幸的是,标准
.iso8601
不起作用,因为 ISO 日期字符串包含小数秒。

或者,如果您对日期不感兴趣,请删除结构中的

startTime
。不需要解码所有密钥。

© www.soinside.com 2019 - 2024. All rights reserved.