[英]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.