如何在我的其余代码执行之前从 URLSession 获得响应?
How do I get the response from a URLSession before the rest of my code executes?
我在 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
.
解决方案可能是将计算Events的部分移到异步块中,并提供一个完成参数:
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([=11=].compactMap(Event.init(fromJSON:))) }
}
我在 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
.
解决方案可能是将计算Events的部分移到异步块中,并提供一个完成参数:
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([=11=].compactMap(Event.init(fromJSON:))) }
}