Swift解析API JSON返回空数组问题求助
问题:API解析JSON后调用getStandings()返回空数组
我尝试从API解析JSON对象,已在单独文件中定义JSON结构。解析器可成功解析JSON,但在viewDidLoad()中调用getStandings()函数时返回空数组。我是新手,试过类似问题的解决方案但无效,以下是我的JSON结构定义和请求解析代码,希望有人指出错误并说明修改方向:
JSON结构定义
struct FootballData : Codable{ let response: [Response] } struct Response: Codable { let league: League } struct League: Codable { let id: Int let name: String let country: String let standings : [[Standings]] } struct Standings: Codable { let rank: Int let team: Team let points: Int let goalsDiff: Int let all: All } struct Team: Codable { let id: Int let name: String let logo: String } struct All: Codable { let played: Int let win: Int let draw: Int let lose: Int }
请求解析代码
func getStandings() -> [[Standings]]{ let standings = [[Standings]]() var request = URLRequest(url: URL(string: "https://v3.football.api-sports.io/standings?league=39&season=2022")!,timeoutInterval: Double.infinity) request.addValue("639248abcf96cbcebd90cd66aec49db4", forHTTPHeaderField: "x-rapidapi-key") request.addValue("v3.football.api-sports.io", forHTTPHeaderField: "x-rapidapi-host") request.httpMethod = "GET" let task = URLSession.shared.dataTask(with: request) { (data, response, error) in if error == nil && data != nil { let decoder = JSONDecoder() do { let decodedData = try decoder.decode(FootballData.self, from: data!) let standings = decodedData.response[0].league.standings print(standings) } catch { print(error) } } } //4. Start the task task.resume() return standings }
问题原因与修改方案
核心错误
URLSession.dataTask是异步执行的网络请求,你调用task.resume()后立刻返回了函数开头定义的空数组standings,此时网络请求还在后台运行,异步闭包里的解析结果根本无法同步影响返回值。另外,闭包里的let standings是局部变量,和函数外层的空数组完全无关,就算解析成功也不会改变返回值。
修改方案:改用闭包回调返回结果
异步操作无法通过同步返回值的方式获取结果,必须用闭包回调来传递解析后的结果或错误:
修改后的getStandings函数
func getStandings(completion: @escaping ([[Standings]]?, Error?) -> Void) { guard let url = URL(string: "https://v3.football.api-sports.io/standings?league=39&season=2022") else { completion(nil, NSError(domain: "URLError", code: 0, userInfo: [NSLocalizedDescriptionKey: "无效的URL"])) return } var request = URLRequest(url: url, timeoutInterval: Double.infinity) request.addValue("639248abcf96cbcebd90cd66aec49db4", forHTTPHeaderField: "x-rapidapi-key") request.addValue("v3.football.api-sports.io", forHTTPHeaderField: "x-rapidapi-host") request.httpMethod = "GET" let task = URLSession.shared.dataTask(with: request) { data, response, error in // 优先处理错误 if let error = error { completion(nil, error) return } // 验证数据是否存在 guard let data = data else { completion(nil, NSError(domain: "DataError", code: 0, userInfo: [NSLocalizedDescriptionKey: "未获取到有效数据"])) return } // 解析JSON let decoder = JSONDecoder() do { let decodedData = try decoder.decode(FootballData.self, from: data) let standings = decodedData.response[0].league.standings completion(standings, nil) } catch { completion(nil, error) } } task.resume() }
在viewDidLoad中的调用方式
override func viewDidLoad() { super.viewDidLoad() getStandings { standings, error in if let error = error { print("请求失败:\(error.localizedDescription)") return } guard let standings = standings else { print("未获取到排名数据") return } // 注意:更新UI必须切换到主线程 DispatchQueue.main.async { // 这里处理获取到的排名数据,比如刷新表格视图 print(standings) } } }
额外注意事项
- 所有UI操作必须在主线程执行,所以在闭包里处理UI时要加上
DispatchQueue.main.async。 - 代码中增加了URL有效性检查和数据存在性验证,避免强制解包导致崩溃。
内容的提问来源于stack exchange,提问作者ZCoder
相关产品推荐
相关产品推荐

