0

Here I'm trying to get currency values of INR for last 30 dates.

I'm fetching last 30 dates values of INR currency using Alamofire.

//strDates contains all 30 days dates

for i in 0..<strDates.count {
    Alamofire.request("http://api.fixer.io/\(strDates[i])?base=USD").responseJSON { response in               
         if let arr = response.result.value as? [String:AnyObject]
         {
             let inrc = (arr["rates"]?["INR"] as? Double)!
             print(inrc)
             self.sValues.append(inc)
             print(sValues)
             //It prints values here.
         }
    }
}
print(sValues) //Print nil

setChart(dataPoints: strDates, values: sValues)

How do I use this sValues array outside the Alamofire block.

Here, Actually I'm sending dates & INR values as a parameter to below method.

func setChart(dataPoints: [String], values: [Double]) {
        barChartView.noDataText = "You need to provide data for the chart."

        for i in 0..<dataPoints.count {
            let dataEntry = BarChartDataEntry(x: Double(i), yValues: [values[i]])
            dataEntries.append(dataEntry)
        }

        let chartDataSet = BarChartDataSet(values: dataEntries, label: "INR Rates(₹)/$")
        let chartData = BarChartData(dataSet: chartDataSet)
        barChartView.data = chartData
        barChartView.xAxis.labelPosition = .bottom
        barChartView.rightAxis.enabled = false
        barChartView.leftAxis.enabled = true
        barChartView.data?.setDrawValues(false)
        barChartView.leftAxis.granularityEnabled = true
        barChartView.leftAxis.granularity = 1.0
        barChartView.xAxis.granularityEnabled = true
        barChartView.xAxis.granularity = 1.0
        barChartView.leftAxis.axisMinimum = 70//65
        barChartView.leftAxis.axisMaximum = 60//70

        //chartDataSet.colors = [UIColor.cyan, UIColor.green]
    }

3 Answers3

0

Your codes cause sValues to print nil because your print(sValues) ran before your request response. This block

if let arr = response.result.value as? [String:AnyObject]
{
    let inrc = (arr["rates"]?["INR"] as? Double)!
    print(inrc)
    self.sValues.append(inc)
    print(sValues)
    //It prints values here.
}

runs only when your request returns with a value or an error. So any usage of values from your request should also be done here. If you want to use the value to update certain UI element or database, you should also call the method from within this block to ensure that you already retrieved the value from its source.

I do suggest you adopt this mentality when programming any asynchronous codes as you can never expect when your codes running in another thread or the server to return. It is always safer to run you methods that requires the return value in a completion block that runs only when the asynchronous codes have completed.

Ben Ong
  • 913
  • 1
  • 10
  • 25
0

If you're displaying them in a table, create a strong variable of type Array, or some other data provider (e.g. CoreData, SQLite) and store the results there. In the completion block for AF, set the value of the Array variable (or update your local data provider) to the API result data, then call reloadData() on your table. You'll also need to configure the UITableView delegate and datasource methods.

brandonscript
  • 68,675
  • 32
  • 163
  • 220
0

Are you looking for the chart to refresh when only when ALL of the calls are done? If so you use a pattern like this:

    var completedCalls = 0
    for i in 0..<strDates.count {
        Alamofire.request("http://api.fixer.io/\(strDates[i])?base=USD").responseJSON { response in
            if let arr = response.result.value as? [String:AnyObject]
            {
                completedCalls += 1
                let inrc = (arr["rates"]?["INR"] as? Double)!
                print(inrc)
                self.sValues.append(inc)
                print(sValues)
                //It prints values here.
                if completedCalls = strDates.count {
                    DispatchQueue.main {
                        setChart(dataPoints: strDates, values: sValues)
                    }
                }
            }
        }
    }

The idea is to count how many API requests come back and only take action when all of the requests are done (you should check that all of them actually succeeded as well and show an error if any fail).

Josh Homann
  • 15,933
  • 3
  • 30
  • 33
  • Hello @Josh, facing new problem. Whenever I open navigate to another view and after coming back to ChartView, bar chart refresh and shows different values. –  Jan 13 '17 at 08:45
  • bar chart refresh and shows different values, everytime whenever I navigate or refresh it. –  Jan 13 '17 at 08:51
  • 1
    For what it's worth, you're better off using a dispatch queue to handle subsequent requests where you need to wait for completion. Look for `dispatch_group_async` and `dispatch_group_notify` and check out http://stackoverflow.com/questions/11909629/waiting-until-two-async-blocks-are-executed-before-starting-another-block. – brandonscript Jan 13 '17 at 18:26