1

I have a function that is build to get the latest items from a API. There are several other ones, with different functionality, but they all work the same. It looks like this:

func getLatest(pageNumber: Int) -> Array<Any>{
    let urlRequest = URL(string: baseUrl + latestUrl + String(pageNumber))

    let requestedData = doRequest(url: urlRequest!, completion: { data -> Void in
        // We have the data from doRequest stored in data, but now what?!

    })

    return allData
}

I also have a async method that handles the requests. That one looks like this:

func doRequest(url: URL, completion: @escaping ([[ApiItem]]) -> ()){
    var allItems = [[ApiItem]]()

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else { return }

        do{
            let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [String: AnyObject]

            let results = json["items"] as? [AnyObject]

            for r in results!{
                let item = ApiItem(json: r as! [String: Any])

                allItems.append([item])
            }

            completion(allItems)
        } catch let jsonError{
            print("JSON error: \(jsonError)")
        }
    }.resume()

The doRequest function works absolutely fine. It gets the data, parses the JSON and send it back to getLatest --> requestedData. The problem right now is, is that getLatest() is a function that needs to return the data that is stored in the data variable of requestedData.

How can I make it so, that the getLatest() function returns the data that is stored in the data in requestedData()?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
kaanmijo
  • 713
  • 1
  • 5
  • 14
  • Give to getLatest the same treatment you gave to doRequest following our comments in your [previous question](https://stackoverflow.com/q/46002165/2227743). *A callback in a callback*. Inside the call to doRequest (where you have your "now what" comment), call the completion handler you will have added to the signature of getLatest. // It works great and I often use it. Beware though to not nest too many callbacks, you would go straight to Inception hell. Two is ok. – Eric Aya Sep 01 '17 at 15:44
  • Thanks! I'ts working right now! – kaanmijo Sep 01 '17 at 16:01
  • Please post your code in an answer, it could be nice for future users to see the complete solution. – Eric Aya Sep 02 '17 at 09:05
  • @Moritz Done! I'll mark it as answer tomorrow. – kaanmijo Sep 02 '17 at 10:33

2 Answers2

0

So I've fixed it by doing this:

In the first method, the one that actually needs the data from the API, I added this:

let trendingData = restApiManager.getLatest(pageNumber: 0, completion: { data -> Void in
   let item = data[indexPath.row]

   let url = NSURL(string: item.still)

   let data = NSData(contentsOf: url as! URL)
   if data != nil {
       cell.image.image = UIImage(data:data! as Data)
   }             
})

The getLatest() method looks like this:

func getLatest(pageNumber: Int, completion: @escaping ([ApiItem]) -> ()) {
    let urlRequest = URL(string: baseUrl + trendingUrl + String(pageNumber))

    let requestedData = doRequest(url: urlRequest!, completion: { data -> Void in
        // We have the data from doRequest stored in data
        var requestedData = data
        completion(requestedData)
    })
}

And finally, the doRequest() method looks like this:

func doRequest(url: URL, completion: @escaping ([ApiItem]) -> ()){
    var allItems = [ApiItem]()

    URLSession.shared.dataTask(with: url) { (data, response, error) in
        guard let data = data else { return }

        do{
            let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [String: AnyObject]

            let results = json["items"] as? [AnyObject]

            for r in results!{
                let item = ApiItem(json: r as! [String: Any])

                allItems.append(item)
            }

            completion(allItems)
        } catch let jsonError{
            print("JSON error: \(jsonError)")
        }
    }.resume()
}
kaanmijo
  • 713
  • 1
  • 5
  • 14
-1

What I would do is use a Singleton in which I can store the Data

class DataManager:NSObject
{
  static let instance  = DataManager()
  override private init(){}


  var items:[ApiItem] = []
}

Then in your first method I would do this:

func getLatest(pageNumber: Int){
    let urlRequest = URL(string: baseUrl + latestUrl + String(pageNumber))

    let requestedData = doRequest(url: urlRequest!, completion: { data -> items in
        // We have the data from doRequest stored in data, but now what?!


      DataManager.instance.items = items
    })

}

This is how I usually go about this kind of situations. There may be better options though...