0

I have some trouble with the code below. Though it works, there is some timing problem.

First let me say what I expect, I suppose the completion handler should be run when the data download is complete and my image ready to use. But reality seems to be quite different. When I try it the completion handler is called right away (I can see 'All OK' in the console) as if everything was instantaneous. But the image gets actually displayed much later. What am I missing?

let imageURL = URL(string: myURLString)
session = URLSession.shared,
_ = session.dataTask(with: imageURL) {[weak self]
    (data: Data?, response: URLResponse?, error: Error?) in
    if error == nil {
        print("All OK")
        self?.theImage = UIImage(data: data!)
        self?.theView.image = self?.theImage
    } else {print(error!)}

    DispatchQueue.main.async {
        self?.activityIndicator.stopAnimating()
        self?.theView.setNeedsDisplay()
    }
    }.resume()
Michel
  • 10,303
  • 17
  • 82
  • 179
  • the handler will be called again when data is loaded and available from server. You should also have added session.finishTasksAndInvalidate() just before your final braces }.resume() – Umar Farooque Aug 16 '17 at 09:21
  • OK. What do you mean by "the handler will be called again"? It is already called. Is supposed to be called multiple times? – Michel Aug 16 '17 at 09:24
  • The control reaches the handler again when data is fetched. Also, the self?.theView.image = self?.theImage should be on Main thread. And which version of swift are you using ? – Umar Farooque Aug 16 '17 at 09:29
  • I am using Swift 3 (Xcode 8.3.3). – Michel Aug 16 '17 at 09:31
  • OK, In other words "control reaches the handler" several times, but when do I know that the data fetch is complete in that case? Since as I wrote in my post, the handler is also reached before the fetch is complete. – Michel Aug 16 '17 at 09:34
  • 1
    Indeed if I put "self?.theView.image = ...." on the main thread, it all works. Thanks a lot. You pointed the right spot. – Michel Aug 16 '17 at 09:40
  • Oh lol, i just put up answer, anyway you are welcome ! – Umar Farooque Aug 16 '17 at 09:42

1 Answers1

1

Can you try this code?

The control should not be actually going inside the handler at first call. And I think there are a few mistakes in your code as well which I pointed out earlier, especially the main thread is required for updating UI.

    let session : URLSession
    let config = URLSessionConfiguration.default
    var resultFromServer: Any?
    let responseResultData = [String:Any]()
    session = URLSession(configuration: config, delegate: nil, delegateQueue: nil)
    session.dataTask(with: request) { (data, response, error ) in

        if error != nil {

            DispatchQueue.main.async(execute: {

                session.invalidateAndCancel()

            })

        }else{

            let httpResponse: HTTPURLResponse = response as! HTTPURLResponse

                do{

                    resultFromServer = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)
                    if httpResponse.statusCode == 200  || httpResponse.statusCode == 201 || httpResponse.statusCode == 202 || httpResponse.statusCode == 204 || httpResponse.statusCode == 203 {

                        if let respArr = resultFromServer as? [Any]{

                          //resp is array


                        }else if let respdict = resultFromServer as? [String : Any] {

                            //resp is dict


                        }else{

                           //resp is something else maybe string, etc

                        }

                    }
                    else {


                       //error status code something like 500, 404, etc

                    }


                }

                catch let error as NSError {

                    DispatchQueue.main.async(execute: {

                        session.invalidateAndCancel()

                    })
                }

            }

        session.finishTasksAndInvalidate()
        }.resume()
Umar Farooque
  • 2,049
  • 21
  • 32