Home > Enterprise >  How to get value out of URLSession
How to get value out of URLSession

Time:11-16

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.
}
  • Related