0

I'm currently trying to create a historical exchange rate graph in swift using BEMSimpleLineGraph, and grabbing data from http://fixer.io/ using AlomoFire. I'm using a for-loop to loop through 7 day(just to see if I can get it working) and then appending (or whatever it's called) the values to an array called xAxisData

func updateGraphData(timeInterval: Int){
    if selectedCurrency1 != nil && selectedCurrency2 != nil { // checking if both currencies have been selected 
        self.xAxisData.removeAll() // removing some default values

        for i in 1...timeInterval { // don't know exactly if i'm doing this the optimal way?
            print("passed")
            let date = Date()
            let dateComponents = Calendar.current.dateComponents([.month, .day,.year], from: date) //getting the the year(again, just to see if it's working)
            historyURL = "http://api.fixer.io/\(dateComponents.year!.description)-03-0\(String(i))?base=\(selectedCurrency1!.rawValue)" //modifying the url to my needs 


            Alamofire.request(historyURL, method: .get).responseJSON { // requesting data
                response in
                if response.result.isSuccess{
                    let json = JSON(response.result.value!)
                    self.xAxisData.append(json["rates"] [self.selectedCurrency2!.rawValue].doubleValue) // using SwiftyJSON btw to convert, but shouldn't this in theory append in the correct order?
                    print(json["date"].stringValue) // printing out the date


                }
                else{
                    print("Error \(String(describing: response.result.error))")
                }
        }

    }
    }
}

CONSOLE:

    []
2017-03-02
2017-03-03
2017-03-01
2017-03-03
2017-03-03
2017-03-06
2017-03-07
[4.5359999999999996, 4.5316000000000001, 4.4739000000000004, 4.5316000000000001, 4.5316000000000001, 4.5133000000000001, 4.4844999999999997]

I know I made the mistake of making the currency values a double when it probably should've been a float. Feel free to ask for more information if needed or to correct my in any other way, as I'm just trying to learn.

I want the output to be in chronological order, so the date goes 1,2,3,4,5,6,7 instead of 2,3,1,3,3,6,7. I'm using using multiple URLs that are modified, api.fixer.io/2017-03-01?base=GB for example.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • 1
    what you want ?? do you want to sort data – Jaydeep Vyas Jul 31 '17 at 11:57
  • You launch a series of http requests at the same time, there is no guarantee they will complete in the same order they were fired. – mag_zbc Jul 31 '17 at 11:58
  • Hi, what exactly you want to achieve and the output you are having, why do you think it is the wrong output. Also it will be helpful if you can post the URL you are generating from http://api.fixer.io/ . – sarosh mirza Jul 31 '17 at 11:59
  • I want the output to be in chronological order, so the date goes 1,2,3,4,5,6,7 instead of 2,3,1,3,3,6,7. I'm using using multiple URLs that are modified, http://api.fixer.io/2017-03-01?base=GB for example. A possible explanation could as mag_zbc suggests, but how do i achieve this – user8288212 Jul 31 '17 at 12:17
  • @user8288212 try my solution which synch the webservice call and also generate different urls – Jaydeep Vyas Jul 31 '17 at 12:20

2 Answers2

1

The problem is that all network requests are asynchronous and there is no guarantee that they will finish execution in the order they are called. Hence, your data in the array is not in the order in which you called the requests.

You can use a serial DispatchQueue to make your requests run in the order you call them, however, this will make your program slower, since it will only execute a single request at a time instead of running all of them in parallel.

A better solution for this particular problem would be to either insert the values from inside the completion handler into the array to a certain index and don't just append them. This way you can make the ordering the same as the API calls' order even though you didn't have to synchronise your API calls. Or you can store the returned values in a dictionary, where the key would be the string representation of the day for which you made the network request.

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
0
  • Create a struct for example

    struct Rate {
        let currency : String
        let date : Date
        var value : Double
    }
    
  • Create an array var historicalRates = [Rate]().

  • In the for loop

    • calculate the date with the Calendar API, your way gets in trouble on overflow to the next month. For example

      let calendar = Calendar.current
      // set the date to noon to avoid daylight saving changes at midnight in a few countries
      let today = calendar.date(bySettingHour: 12, minute: 0, second: 0, of:  Date())!
      
      let formatter = DateFormatter()
      formatter.dateFormat = "yyyy-MM-dd"
      
      for dayOffset in 0...7 {
          let currentDate = calendar.date(byAdding: .day, value: dayOffset, to: today)!
          let currentDateAsString = formatter.string(from: currentDate)
          print(currentDate, currentDateAsString)
      }
      
    • create a Date from the current date.

    • create a Rate instance with actual date and name, add it to the historicalRates and pass it to the asynchronous task.
  • Assign the rate value in the completion block.
  • Use DispatchGroup to get notified when the loop is finished.
  • Finally sort historicalRates by date.
vadian
  • 274,689
  • 30
  • 353
  • 361