如何使用转义闭包和异步调用加载UI?

时间:2017-05-15 16:43:55

标签: swift asynchronous escaping closures api-design

我编写了一个名为'configureLabels()'的函数,该函数应该发出'GET'请求并检索一个值,然后将该值设置为标签的文本。该请求是异步的,所以我认为我可以使用转义闭包来在请求完成时更新UI。我对编码比较陌生,所以我不确定我做错了什么。我非常感谢任何人帮助解决这个问题。

这是包含'configureLabels()'方法的代码:

import UIKit

导入SwiftyJSON

class ItemDetailViewController:UIViewController {

@IBOutlet weak var numberOfFiberGrams: UILabel!

var ndbnoResults = [JSON]()
var ndbno = ""

let requestManager = RequestManager()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    configureLabels()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}


func configureLabels() {

    requestManager.ndbnoRequest(ndbno: ndbno) { (results) in
        let json = JSON(results)
        let fiber = json["food"]["nutrients"][7].dictionaryValue
        for (key, value) in fiber {
            if key == "value" {
                self.numberOfFiberGrams.text = "\(value.stringValue)"
            } else {
                self.numberOfFiberGrams.text = "Fail"
            }
        }
    }
}

/*
// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
}
*/

}

以下是包含'configureLabels()'调用函数的代码:

    func ndbnoRequest(ndbno: String, apiKey: String, completionHandler: @escaping (_ results: JSON?) -> Void) {
    Alamofire.request("https://api.nal.usda.gov/ndb/V2/reports?ndbno=\(ndbno)&type=f&format=json&api_key=\(apiKey)", method: .get).validate().responseJSON { response in
        switch response.result {
        case .success(let value):
            let json = JSON(value)
            completionHandler(json)
            print("successful ndbno request")
        case .failure(let error):
            completionHandler(nil)
            print(error)
        }
    }
}

2 个答案:

答案 0 :(得分:0)

您的代码看起来没问题我在您的代码中找到的问题是您没有在completionHandler部分调用failure,您需要始终调用完成块,这样它会让您知道吗?您completionHandler参数的响应与[JSON]的类型是failure,因为您没有在completionHandler部分回复,而您没有在其中调用optional。如果completionHandler,您可以执行nil并使用failure参数调用func ndbnoRequest(ndbno: String, completionHandler: @escaping (_ results: [JSON]?) -> Void) { let parameters = ["api_key": "tIgopGnvNSP7YJOQ17lGVwazeYI1TVhXNBA2Et9W", "format": "json", "ndbno": "\(ndbno)"] Alamofire.request("https://api.nal.usda.gov/ndb/reports/V2", method: .get, parameters: parameters).responseJSON { response in switch response.result { case .success(let value): let json = JSON(value) let ndbnoResults = json["foods"].arrayValue completionHandler(ndbnoResults) print("successful ndbno request") case .failure(let error): completionHandler(nil) print("error with ndbno request") } } }

requestManager.ndbnoRequest(ndbno: ndbno) { (results) in
    if let result = results {
        let json = JSON(result)
        let fiber = json["food"]["nutrients"][7].dictionaryValue
        for (key, value) in fiber {
            if key == "value" {
                self.numberOfFiberGrams.text = "\(value.stringValue)"
            } else {
                self.numberOfFiberGrams.text = "Fail"
            }
        }
    }
    else {
        print("Problem to get response")
    }
}

现在以这种方式调用它并将可选项包装在完成块中,以便确认您得到响应。

setValues()

答案 1 :(得分:0)

与UI相关的所有内容必须在主线程上始终完成。 所以试试这个:

DispatchQueue.main.async {
    let json = JSON(results)
    let fiber = json["food"]["nutrients"][7].dictionaryValue
    for (key, value) in fiber {
        if key == "value" {
            self.numberOfFiberGrams.text = "\(value.stringValue)"
        } else {
            self.numberOfFiberGrams.text = "Fail"
        }
    }
}

P.S。我同意Nirav关于失败回调 - 你也应该处理它。我强烈建议你给函数和变量提供更具可读性和有意义的名称,而不是" ndbnoRequest"和" ndbno"。你不会记得几周内的意思:)