I keep coming back to the same problem. For other parts of my app I used coredata directly after parsing the API and that works fine. However, now I want to parse a JSON received through an API and just get one value that I use to calculate other values which I then put in Coredata.
Everything works fine and I have set up the URLSessions code as follows:
func fetchData(brand: String, completion: @escaping ((Double) -> Void)) {
let urlString = "\(quoteUrl)\(brand)"
if let url = URL(string: urlString) {
var session = URLRequest(url: url)
session.addValue("application/json", forHTTPHeaderField: "Accept")
session.addValue("Bearer \(key)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: session) { (data, response, error) in
if error != nil {
print(error!)
return
}
if let safeData = data {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(DataModel.self, from: safeData)
let bid = decodedData.quotes.quote.bid
let ask = decodedData.quotes.quote.ask
let itemPrice: Double = (bid ask)/2
completion(itemPrice)
} catch {
print(error)
}
}
}
task.resume()
}
}
I am using the completionHandler to retrieve the part I need which I use in another file as follows:
func getGainLossNumber(brand: String, quantity: Int, price: Double) -> Double {
var finalPrice = 0.0
APImodel.fetchData(brand: brand) { returnedDouble in
let currentPrice = returnedDouble
if quantity < 0 {
let orderQuantity = quantity * -1
finalPrice = price (currentPrice*(Double(orderQuantity))*100)
} else {
finalPrice = price - (currentPrice*(Double(quantity))*100)
}
}
return finalPrice
}
finalPrice eventually returns 0.0. If I print currentPrice in the closure I do get the correct result. I used the completion handler in order to retrieve a number from the API because of the issues I was facing but it stil is not doing what I would like to have. The second function should return the value that was calculated using the value I got from the API that I retrieved with the completion handler.
I just can't figure out how to do it.
CodePudding user response:
The problem is that you are calculating finalPrice
inside a closure, which is asynchronous. Your getGainLossNumber method however, is synchronous, so it actually returns before your closure is finished calculating finalPrice
. Restructure your code so that getGainLossNumber
takes a closure as a parameter, and invokes it once finalPrice
has been calculated. Something like:
func getGainLossNumber(brand: String, quantity: Int, price: Double, _ completion: @escaping (Double) -> Void) {
APImodel.fetchData(brand: brand) { returnedDouble in
let currentPrice = returnedDouble
let finalPrice: Double
if quantity < 0 {
let orderQuantity = quantity * -1
finalPrice = price (currentPrice*(Double(orderQuantity))*100)
}
else {
finalPrice = price - (currentPrice*(Double(quantity))*100)
}
completion(finalPrice)
}
}
Also note, that finalPrice does not need to be var as it will be assigned a value only once.
EDIT
Usage:
getGainLossNumber(brand: "brand", quantity: 1, price: 120, { finalPrice in
// You can access/use finalPrice in here.
}