json - 如何在执行其余代码之前从 URLSession 获取响应?
问题描述
我在 Swift 中的 URLSession 有问题。无论我尝试什么(或阅读了多少教程),我都找不到在执行其余代码之前完成网络请求的方法。我的印象是完成处理程序可以解决问题,但事实并非如此。我在这里做错了什么?
struct DataManager {
let eventsURL = URL(string: "https://spreadsheets.google.com/feeds/list/blablabla/1/public/full?alt=json")!
let decoder = JSONDecoder()
var data = Data()
func downloadEvents() -> [Event] {
var events: [Event] = []
var downloadedEvents: [[String: Any]] = []
getDataFromServer(forURL: eventsURL) { result in
downloadedEvents = result
}
// This next part always executes before the response is receive, which means the downloadedEvents variable is always empty.
for downloadedEvent in downloadedEvents {
if let event = Event(fromJSON: downloadedEvent) {
events.append(event)
}
}
return events
}
func getDataFromServer(forURL url: URL, completion: @escaping (_ result: [[String: Any]]) -> Void) {
URLSession.shared.dataTask(with: url) { data, response, error in
if let jsonData = data {
let jsonObject = try? JSONSerialization.jsonObject(with: jsonData, options: [])
if let dictionary = jsonObject as? [String: Any] {
if let feed = dictionary["feed"] as? [String: Any] {
if let entry = feed["entry"] as? [[String: Any]] {
DispatchQueue.main.async {
completion(entry)
}
}
}
}
}
}.resume()
}
}
解决方案
您的downloadEvents
函数需要是异步的,因为它调用另一个异步函数getDataFromServer
。
解决方案可能是将计算事件的部分移到异步块中并提供完成参数:
func downloadEvents(completion: @escaping ([Event]) -> ()) {
var events: [Event] = []
var downloadedEvents: [[String: Any]] = []
getDataFromServer(forURL: eventsURL) { result in
downloadedEvents = result
for downloadedEvent in downloadedEvents {
if let event = Event(fromJSON: downloadedEvent) {
events.append(event)
}
}
completion(events)
}
}
笔记
您的代码实际上可以简化为:
func downloadEvents(completion: @escaping ([Event]) -> ()) {
getDataFromServer(forURL: eventsURL) { completion($0.compactMap(Event.init(fromJSON:))) }
}
推荐阅读
- post - 使用 access.log 重播 POST 日志
- apache-spark - 按 ID 停止 spark 运行流
- eloquent - 我正在学习 laravel 8,但不理解这种语法是如何工作的
- java - 将 if else 重构为 Java 中的单行条件语句?
- flutter - Flutter Firestore ArrayNotContains?
- jenkins - 需要在电子邮件正文中发送测试结果,但未在 Target 文件夹中创建 emailable-report.html
- php - HTML 表单操作 url 为在子域之外复制的 php 文件抛出 404
- python - 返回具有与 dict 相同键的 dict 列表
- regex - 正则表达式集包含一个或多个单词
- javascript - 遍历对象数组并获得一个新的对象数组