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.

5
  • 1
    what you want ?? do you want to sort data Commented Jul 31, 2017 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. Commented Jul 31, 2017 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 api.fixer.io . Commented Jul 31, 2017 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, api.fixer.io/2017-03-01?base=GB for example. A possible explanation could as mag_zbc suggests, but how do i achieve this Commented Jul 31, 2017 at 12:17
  • @user8288212 try my solution which synch the webservice call and also generate different urls Commented Jul 31, 2017 at 12:20

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

Comments

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.

2 Comments

sorting by dates as strings should be enough in this case.
Thanks, this helped!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.