Holmes
Holmes

Reputation: 27

Swift function not returning API calls consistently when looping

Hi I am new to swift and currently learning json and APIs by playing with API from cryptocompare in Playground, rate limit for seconds is 15 per second, I am not getting the desired amount of return in my loop

this is my code

func getPrice(coinSymbol: String, currency: String, day: Date, 
completion: @escaping (Double?) -> Void) {
    let baseURL = URL(string: "https://min-api.cryptocompare.com/data/dayAvg")!
    let query: [String: String] = ["fsym": coinSymbol, "tsym": currency, "toTs": String(format:"%.0f", day.timeIntervalSince1970)]
    let url = baseURL.withQueries(query)!
    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        if let data = data,
            let rawJSON = try? JSONSerialization.jsonObject(with: data), //convert data into native swift values
            let json = rawJSON as? [String: Any]{
            if let price = json[currency] as? Double {
                completion(price)
            } else {
                print("price not found")
            }
        } else {
            print("Either no data was returned or data was not serialised.")
            return
        }
    }
    task.resume()
}

//lastMonth is an Array, [Date] with count of 31

for day in lastMonth {
    getPrice(coinSymbol: "BTC", currency: "USD", day: day) { (price) in
        if let price = price {
            print(price)
        }
    }
}

this is my return in Playground

6738.16
6253.38
6346.16
6588.89
6705.49
.
.
.
price not found
price not found
8248.19
price not found
price not found
price not found
price not found
price not found
7572.14
7406.26
6998.43
7151.93
6993.97

Everytime it refreshes it prints different number of price but seldom do I get my desired 31 price. Is there anyway for me to make sure my function print the exact amount of price consistently in this loop?

Thanks alot

Upvotes: 1

Views: 1365

Answers (2)

Nuria Ruiz
Nuria Ruiz

Reputation: 149

When I run this code in the playground in some request I get the following JSON response:

["MaxLimits": {
    Hour = 8000;
    Minute = 300;
    Second = 15;
}, "Message": Rate limit excedeed!, "Data": <__NSArray0 0x60400000d680>(
)
, "Aggregated": 0, "YourCalls": {
    hour =     {
        Histo = 489;
    };
    minute =     {
        Histo = 16;
    };
    second =     {
        Histo = 16;
    };
}, "Type": 99, "Response": Error].

Even though I put a sleep of five seconds after each call. But when I run it in a project the code is executing correctly and I receive a valid response for each day. Maybe a playground error?

Upvotes: 0

Gereon
Gereon

Reputation: 17882

Your playground finishes executing after the for-loop, and does not wait for all asynchronous requests to return. You need to wait for them manually, like so:

let group = DispatchGroup()

for day in lastMonth {
    group.enter()
    getPrice(coinSymbol: "BTC", currency: "USD", day: day) { (price) in
        if let price = price {
            print(price)
        }
        group.leave()
    }
}

group.notify(queue: DispatchQueue.main) {
    print("done")
    exit(0)
}
dispatchMain()

Upvotes: 4

Related Questions