簡體   English   中英

Swift URLSession完成處理程序

[英]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)
}

將會發生以下情況:

  1. 調用viewDidLoadbackendURLs為零
  2. 您調用getBackendURLs ,它在后台某處的另一個線程處開始​​。
  3. 在此之后,您的代碼會立即繼續到外部print(backendURLs) ,因為backendURLs仍為nil,因此打印nil,因為尚未調用您的回調,因為getBackendURLs仍在另一個線程上工作。
  4. 在稍后的某個時刻,您的getBackendURLs完成檢索數據和解析並執行此行completion(json)
  5. 現在,您的回調函數將通過數組執行,並且您的內部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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM