Swift 4中使用SwiftyJSON解析NBA赛事统计JSON数据求助
Hey there! Let's get your NBA standings parsing sorted out. The main issue with your current code is that you're not navigating the actual structure of the NBA API's JSON response correctly—let's walk through this step by step.
First, Understand the API's JSON Structure
The NBA standings API returns a resultSets array, where each entry contains:
headers: An array of string labels for each data field (like "TeamName", "WINS", "LOSSES", "WIN_PCT")rowSet: An array of arrays, where each inner array represents a single team's stats (ordered to match theheaderslist)
You can't directly access json["Warriors"] because the team data isn't stored under a named key—it's in the rowSet array entries.
Working Code Implementation
Here's a corrected version that finds the Golden State Warriors and extracts their key stats:
import SwiftyJSON // Note: Using Data(contentsOf:) is synchronous and will block the main thread. // For production code, use URLSession's async request (example below) let urlString = "http://stats.nba.com/stats/leaguestandingsv3?LeagueID=00&Season=2017-18&SeasonType=Regular+Season" guard let url = URL(string: urlString) else { print("Invalid URL provided") return } do { let nbaData = try Data(contentsOf: url) let json = try JSON(data: nbaData) // Grab the first result set (this contains the regular season standings data) guard let standingsResultSet = json["resultSets"].array?.first else { print("No standings data found in the response") return } // Extract headers to map field names to their index in the row arrays let statHeaders = standingsResultSet["headers"].arrayValue.map { $0.stringValue } // Extract all team data rows let teamRows = standingsResultSet["rowSet"].arrayValue // Loop through rows to find the Golden State Warriors for teamRow in teamRows { // Locate the "TeamName" field index and check if it's the Warriors guard let teamNameIndex = statHeaders.firstIndex(of: "TeamName"), let teamName = teamRow[teamNameIndex].string, teamName == "Golden State Warriors" else { continue } // Get indices for the stats we want let winIndex = statHeaders.firstIndex(of: "WINS")! let lossIndex = statHeaders.firstIndex(of: "LOSSES")! let winPctIndex = statHeaders.firstIndex(of: "WIN_PCT")! let confRankIndex = statHeaders.firstIndex(of: "ConferenceRank")! // Extract the values let wins = teamRow[winIndex].intValue let losses = teamRow[lossIndex].intValue let winPercentage = teamRow[winPctIndex].doubleValue let conferenceRank = teamRow[confRankIndex].intValue // Print or use the stats print("Golden State Warriors 2017-18 Regular Season Stats:") print("Conference Rank: \(conferenceRank)") print("Wins: \(wins) | Losses: \(losses)") print("Win Percentage: \(String(format: "%.3f", winPercentage))") // Exit loop once we find the Warriors break } } catch { print("Error handling data: \(error.localizedDescription)") }
Better Practice: Asynchronous Network Request
Using Data(contentsOf:) blocks the main thread, which is bad for user experience. Here's how to do it asynchronously with URLSession:
import SwiftyJSON let urlString = "http://stats.nba.com/stats/leaguestandingsv3?LeagueID=00&Season=2017-18&SeasonType=Regular+Season" guard let url = URL(string: urlString) else { print("Invalid URL") return } URLSession.shared.dataTask(with: url) { data, response, error in guard let data = data, error == nil else { print(error?.localizedDescription ?? "Unknown network error") return } do { let json = try JSON(data: data) // Reuse the parsing logic from the synchronous example here guard let standingsResultSet = json["resultSets"].array?.first else { print("No standings data found") return } let statHeaders = standingsResultSet["headers"].arrayValue.map { $0.stringValue } let teamRows = standingsResultSet["rowSet"].arrayValue for teamRow in teamRows { guard let teamNameIndex = statHeaders.firstIndex(of: "TeamName"), let teamName = teamRow[teamNameIndex].string, teamName == "Golden State Warriors" else { continue } let winIndex = statHeaders.firstIndex(of: "WINS")! let lossIndex = statHeaders.firstIndex(of: "LOSSES")! let winPctIndex = statHeaders.firstIndex(of: "WIN_PCT")! let wins = teamRow[winIndex].intValue let losses = teamRow[lossIndex].intValue let winPct = teamRow[winPctIndex].doubleValue print("Warriors Stats (Async):") print("Wins: \(wins), Losses: \(losses), Win %: \(winPct)") break } } catch { print("Parsing error: \(error.localizedDescription)") } }.resume()
Key Notes
- We use the
headersarray to find the index of each stat field—this makes the code resilient if the API changes the order of fields (as long as the field names stay the same) - The team name we check for is the full official name: "Golden State Warriors" (not just "Warriors")
- Always handle optional values safely with
guardto avoid crashes
*Your welcome stats analysts ;)
内容的提问来源于stack exchange,提问作者husharoonie

