无法在URLSession dataTask函数作用域外访问API解码后的JSON数据
问题根因
你遇到的是异步操作时序问题:URLSession.shared.dataTask 是异步执行的网络请求任务,调用task.resume()之后任务会在后台线程运行,不会阻塞当前线程后续代码的执行。所以你写在task.resume()之前的print(jsonData[0].id)会在网络请求还没返回、jsonData还没被赋值的时候就执行,自然拿不到数据。就算你把jsonData改成全局变量,只要你在请求完成前就去读取它,也只能读到初始空值。
解决方案
步骤1:修改回调闭包,将解析完成的数据向外传递
把原来无返回值的回调改成可以携带解析好的[API_data]结果的类型:
// 数据结构定义保持不变 struct API_data: Codable { let id : String } // 修改getJSON函数的回调参数,支持向外传递结果和错误 func getJSON(completed: @escaping ([API_data]?, Error?) -> Void) { let url = "URL Here" // 替换为你的实际请求地址 let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { data,response,error in // 先处理网络错误 guard let data = data, error == nil else{ completed(nil, error) return } do{ let jsonData = try JSONDecoder().decode([API_data].self,from:data) // 解析成功,将数据通过回调传出 completed(jsonData, nil) } catch{ // 解析失败,传出错误信息 completed(nil, error) } }) task.resume() }
步骤2:调用函数,在回调中接收数据并存储/使用
如果你需要在其他地方使用数据,可以在回调触发后(也就是请求完成的时间点)把数据存入全局变量、或者当前类的属性中,之后再使用:
// 示例:在业务类中使用 // 定义属性存储请求到的数据 var storedApiData: [API_data] = [] // 调用请求方法 getJSON { [weak self] resultData, error in // 涉及UI更新的操作需要切换到主线程执行 DispatchQueue.main.async { if let error = error { print("请求失败:\(error.localizedDescription)") return } guard let resultData = resultData, !resultData.isEmpty else { print("返回数据为空") return } // 存储数据到属性 self?.storedApiData = resultData // 所有依赖该接口数据的逻辑都可以在这里执行 print(resultData[0].id) // 比如刷新列表:self?.tableView.reloadData() } }
注意事项
- 不要在调用
getJSON之后立刻读取存储数据的属性,此时请求还未完成,属性仍然是空值。所有依赖该接口返回数据的逻辑,都要放在回调触发之后执行。 - 涉及UI更新的操作必须切换到主线程执行,避免出现界面异常或者崩溃。
内容的提问来源于stack exchange,提问作者pr0grmr
相关产品推荐
相关产品推荐

