启动时未显示API结果

时间:2018-12-04 13:47:15

标签: ios xcode

我正在开发一个应用程序,该应用程序从coindesks API获取信息,该信息会响应JSON,然后进行解析,并显示当前的比特币价格指数,图表名称等。我创建了NetworkingManager单例类,在其中进行GET要求使用AlamoFire吊舱,一切正常,这是NetworkingManager代码:

static let shared = NetworkManager()

let baseURL = "https://api.coindesk.com/v1/bpi/currentprice.json"

var btcEUR : String = ""
var btcGBP : String = ""
var btcUSD : String = ""

var eurSymbol : String = ""
var gbpSymbol : String = ""
var usdSymbol : String = ""

var chartName : String = ""
var timeUpdated : String = ""


private init() {
    getBitcoinData(url: baseURL)
}

func getBitcoinData(url: String) {

    Alamofire.request(url, method: .get)
        .responseJSON { response in
            if response.result.isSuccess {
                print("Sucess! Got the bitcoin price data")
                let responseJSON : JSON = JSON(response.result.value!)
                self.updateBitcoinData(bitcoinJSON : responseJSON)
            }
            else{
                print("Error \(String(describing: response.result.error))")
            }
    }
}

func updateBitcoinData(bitcoinJSON: JSON){
    print("Parsing the JSON")
    self.btcUSD =  bitcoinJSON["bpi"]["USD"]["rate"].string!
    self.btcGBP =  bitcoinJSON["bpi"]["GBP"]["rate"].string!
    self.btcEUR =  bitcoinJSON["bpi"]["EUR"]["rate"].string!

    self.usdSymbol = bitcoinJSON["bpi"]["USD"]["symbol"].string!.html2String
    self.gbpSymbol = bitcoinJSON["bpi"]["GBP"]["symbol"].string!.html2String
    self.eurSymbol = bitcoinJSON["bpi"]["EUR"]["symbol"].string!.html2String

    self.chartName = bitcoinJSON["chartName"].string!
    self.timeUpdated = self.convertUTCDateToLocalDate(dateToConvert: bitcoinJSON["time"]["updated"].string!)
    print("JSON finished parsing")
}

func convertUTCDateToLocalDate(dateToConvert:String) -> String {
    let format = DateFormatter()
    format.dateFormat = "MMM  dd, yyyy HH:mm:ss Z"
    let convertedDate = format.date(from: dateToConvert)
    format.timeZone = TimeZone.current
    format.dateFormat = "MMM  dd, yyyy HH:mm:ss ZZZZZ"
    let localDateStr = format.string(from: convertedDate!)
    return localDateStr
}

func getEurBTC() -> String {
    return btcEUR
}

func getGbpBTC() -> String {
    return btcGBP
}

func getUsdBTC() -> String {
    return btcUSD
}

func getEurSymbol() -> String {
    return eurSymbol
}

func getGbpSymbol() -> String {
    return gbpSymbol
}

func getUsdSymbol() -> String {
    return usdSymbol
}

func getChartName() -> String {
    return chartName
}

func getTimeUpdated() -> String {
    return timeUpdated
}

我遇到的问题是,在VC类中启动时,我希望该应用程序已经向用户显示比特币价格,chartName等。但是,如果我尝试在viewDidLoad中添加updateBitcoinData()函数或viewWillLoad,在启动时它们似乎是空字符串,好像NetworkingManager类无法完成其工作并且未将解析的JSON值分配给所需的变量一样,但是,如果我开始使用pickerView,它将开始显示解析的数据。

以下是显示我的问题的GIF:https://giphy.com/gifs/7Tf2jALO7YF6eE8jCA

这是VC类:

let NetworkingHelper = NetworkManager.shared

let currencyArray = ["USD", "GBP", "EUR" ]
var currencySelected = ""

var USDBTC: String = ""
var GBPBTC: String = ""
var EURBTC: String = ""

var chart : String = ""
var time : String = ""


//Pre-setup IBOutlets
@IBOutlet weak var bitcoinPriceLabel: UILabel!
@IBOutlet weak var currencyPicker: UIPickerView!
@IBOutlet weak var chartName: UILabel!
@IBOutlet weak var timeUpdated: UILabel!

@IBAction func exchangeButtonPressed(_ sender: Any) {
    let main = UIStoryboard(name: "Main", bundle: nil)
    let calculatorvc = main.instantiateViewController(withIdentifier: "SecondVC")
    self.present(calculatorvc,animated: true, completion: nil)
}

override func viewWillAppear(_ animated: Bool) {
    updateBitcoinData()
}

override func viewDidLoad() {
    super.viewDidLoad()
    currencyPicker.delegate = self
    currencyPicker.dataSource = self
}


//MARK: - Pickerview
/***************************************************************/

func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return 1
}

func pickerView(_ pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? {
    currencySelected = currencyArray[row]
    let myTitle = NSAttributedString(string: currencySelected, attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])

    return myTitle
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return currencyArray.count
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return currencyArray[row]
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    currencySelected = currencyArray[row]
    updateBitcoinData()
    switch currencySelected {
    case "USD":
        bitcoinPriceLabel.text = USDBTC
    case "GBP":
        bitcoinPriceLabel.text = GBPBTC
    case "EUR":
        bitcoinPriceLabel.text = EURBTC
    default:
        bitcoinPriceLabel.text = USDBTC

    }
}

//MARK: - Assigning the view
/***************************************************************/

func updateBitcoinData() {
    bitcoinPriceLabel.text = NetworkManager.shared.getUsdSymbol() + NetworkManager.shared.getUsdBTC()
    chartName.text = NetworkManager.shared.getChartName()
    timeUpdated.text = NetworkManager.shared.getTimeUpdated()
    USDBTC = NetworkManager.shared.getUsdSymbol() + NetworkManager.shared.getUsdBTC()
    GBPBTC = NetworkManager.shared.getGbpSymbol() + NetworkManager.shared.getGbpBTC()
    EURBTC = NetworkManager.shared.getEurSymbol() + NetworkManager.shared.getEurBTC()
}

1 个答案:

答案 0 :(得分:0)

似乎在您要更新标签时您的数据不存在。在print("something")中插入另一个updateBitcoinData(),看看它是否在Alamofire请求中的打印之前被调用。

最简单的解决方案是为ViewController注册一个自定义Notification,该自定义class YourViewController: UIViewController { // ... deinit() { NotificationCenter.default.removeObserver(self) } // ... override func viewDidLoad() { // ... NotificationCenter.default.addObserver(self, selector: #selector(bitcoinDataReceived(_:)), name: NSNotification.Name(rawValue: "ReceivedBitcoinData"), object: nil) // ... } // ... @objc func bitcoinDataReceived(_ notification: Notification) { updateBitcoinData() } } 在请求的响应返回数据时由NetworkManager发出。您还可以编写带有完成处理程序的函数,该函数在接收到数据时被调用。

通知解决方案

在您的ViewController类中实现:

class NetworkManager {
    // ...
    func getBitcoinData(url: String) {

        Alamofire.request(url, method: .get)
            .responseJSON { response in
                if response.result.isSuccess {
                    print("Sucess! Got the bitcoin price data")
                    let responseJSON : JSON = JSON(response.result.value!)
                    self.updateBitcoinData(bitcoinJSON : responseJSON)

                    DispatchQueue.main.async {
                        NotificationCenter.default.post(name: Notification.Name.init("ReceivedBitcoinData"), object: nil)
                    }
                }
                else{
                    print("Error \(String(describing: response.result.error))")
            }
        }
    }
// ...
}

在您的NetworkManager类中:

Notification.Name

您还可以为extension Notification.Name { static let ReceivedBitcoinData = Notification.Name.init("ReceivedBitcoinData") } 写一个扩展名,以避免由于输入错误而没有收到通知。

NotificationCenter.default.post(name: .ReceivedBitcoinData, object: nil)

扩展名用法示例:

update_board = ["#"," "," "," "," "," "," "," "," "," "]

def player_turn():
    # Take in player's input so it can be added to the display board.
    user_input = input('Choose your position: ')

    if update_board[int(user_input)] == " ":
        valid_input = True
    else:
        valid_input = False

    while not valid_input:
        user_input = input("That is not an option, please try again.\n> ")
        if update_board[int(user_input)] == " ":
             valid_input = True
        else:
             valid_input = False  

    return int(user_input)

player1 = "X"
update_board[(player_turn())] = player1