[英]Swift URLSession completion Handler
我正在尝试在我的Swift项目中进行API调用 。 我刚刚开始实现它,并且试图从调用中返回Swift字典 。
但我认为我在完成处理程序中做错了! 我无法从API调用中获取返回值。
import UIKit
import WebKit
import SafariServices
import Foundation
var backendURLs = [String : String]()
class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate {
@IBOutlet var containerView : UIView! = nil
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
self.getBackendURLs { json in
backendURLs = self.extractJSON(JSON: json)
print(backendURLs)
}
print(backendURLs)
}
func getBackendURLs(completion: @escaping (NSArray) -> ()) {
let backend = URL(string: "http://example.com")
var json: NSArray!
let task = URLSession.shared.dataTask(with: backend! as URL) { data, response, error in
guard let data = data, error == nil else { return }
do {
json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSArray
completion(json)
} catch {
#if DEBUG
print("Backend API call failed")
#endif
}
}
task.resume()
}
func extractJSON(JSON : NSArray) -> [String : String] {
var URLs = [String : String]()
for i in (0...JSON.count-1) {
if let item = JSON[i] as? [String: String] {
URLs[item["Name"]! ] = item["URL"]!
}
}
return URLs
}
}
第一个print()语句为我提供了正确的值,但第二个为“ nil”。
有人对我做错了什么建议吗?
从技术上说,@ lubilis已经回答了,但我不能在评论中注明,所以请耐心等待。
这是您的viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.getBackendURLs { json in
backendURLs = self.extractJSON(JSON: json)
print(backendURLs)
}
print(backendURLs)
}
将会发生以下情况:
viewDidLoad
, backendURLs
为零 getBackendURLs
,它在后台某处的另一个线程处开始。 print(backendURLs)
,因为backendURLs
仍为nil,因此打印nil,因为尚未调用您的回调,因为getBackendURLs
仍在另一个线程上工作。 getBackendURLs
完成检索数据和解析并执行此行completion(json)
print(backendURLs)
被称为...,并且backendURLs
现在具有一个值。 为了解决您的问题,您需要在回调方法中刷新数据。
如果它是UITableView
,则可以进行reloadData()
调用,或者编写一种方法来为您更新UI。 重要的部分是您在回调内更新UI,因为在那之前您没有有效的值。
在对此答案的评论中,您说:
我需要在complementHandler之后立即访问变量backendURLs
为此,您可以创建一个新方法:
func performWhateverYouNeedToDoAfterCallbackHasCompleted() {
//Now you know that backendURLs has been updated and can work with them
print(backendURLs)
//do what you must
}
然后在回调self.getBackendURLs
其发送到self.getBackendURLs
,您将调用该方法,并且如果您想确保它在主线程上发生,您已经确定了:
self.getBackendURLs { json in
backendURLs = self.extractJSON(JSON: json)
print(backendURLs)
DispatchQueue.main.async {
self.performWhateverYouNeedToDoAfterCallbackHasCompleted()
}
}
现在,在回调完成后将调用您的方法。
由于您的getBackendURLs
是一个异步方法,因此您不知道它何时完成,因此您不能期望从getBackedURLs
获得的值在调用getBackendURLs
之后getBackendURLs
准备好,直到getBackendURLs
实际上完成并准备调用其回调方法之前,它们才准备就绪。
希望有道理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.