繁体   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