-1

I can't change my view until my request and to find and fill my object.

I tried to put my code assync with GCD. That don't work

override func viewDidLoad() {
    getHeartStroke()
NotificationCenter.default.addObserver(forName:NSNotification.Name("HeartStrokeNotification"), object: nil, queue: nil, using: notificationFinish)
 }

 func getHeartStroke() {
AF.request("http://localhost:8080/heartstroke", method: .get, headers: nil).responseJSON(completionHandler: {response in
    if (response.error == nil)
    {
        let json = JSON(response.result.value!)
            DispatchQueue.global(qos: .userInitiated).async {
                guard let hearstrokeArray = try? JSONDecoder().decode([HeartStroke].self, from: json.rawData()) else{
                    debugPrint("An error has occurred")
                    return
                }
                NotificationCenter.default.post(name:NSNotification.Name("HeartStrokeNotification"), object: hearstrokeArray, userInfo: nil)
            }
        }else{
            NotificationCenter.default.post(name:NSNotification.Name("HeartStrokeErrorNotification"), object: nil, userInfo: nil)
        }
    })
 }

 func notificationFinish(notification:Notification) -> Void{
  if (notification.name.rawValue == "HeartStrokeNotification"){

    arrayHeartstroke = notification.object as! [HeartStroke]
    DispatchQueue.main.async(execute: {
        self.tableView.reloadData()
    })
}

With this code I stay block on my page until the end of getHeartStroke(), I expect to navigate in my app in same time of the fetch.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Badr Filali
  • 279
  • 5
  • 21

1 Answers1

0

What you need is a completion handler to handle this. Using the notification centre is just making your life difficult and complicated and could lead to unexpected behaviour. Here is some sample code:

func getHeartStroke(completionHandler: (_ heartStroke: [HeartStroke?], _ error: NSError?) -> ()) {
    AF.request("http://localhost:8080/heartstroke", method: .get, headers: nil).responseJSON(completionHandler: {response in
        if (response.error == nil)
        {
            let json = JSON(response.result.value!)
            DispatchQueue.global(qos: .userInitiated).async {
                guard let hearstrokeArray = try? JSONDecoder().decode([HeartStroke].self, from: json.rawData()) else{
                    debugPrint("An error has occurred")
                    return
                }
                completionHandler(hearstrokeArray, nil)
            }
        } else {
            completionHandler(nil, response.error))
        }
    })
}

Then you can call it like so:

getHeartStroke { [weak self] (heartStrokeArray, error) in
     guard let self = self else {return}
        if error != nil {
            self.processError(error)
        } else {
            self.processHeartStroke(heartStrokeArray)
        }
    }

processError and processHeartStroke will be functions that you should create to handle the heartStrokeArray and error objects.

These are standard callbacks or passing functions into functions. A lot of courses you find online seem to ignore callbacks but its definitely worth your time learning about them.

You can learn more about closures (completionHandler as one is named here) here: https://docs.swift.org/swift-book/LanguageGuide/Closures.html

paul_f
  • 1,296
  • 17
  • 20
  • Well this code certainly works asynchronously. Straight after the final bracket of the AF request but inside the getHeartStroke function add your code to move to the next view. All you need to do there is make sure the view is set up to wait for the data rather than requiring it when it is instantiated. From what are telling me it sounds like your problem is on the next view not this view and they Way it requires data as soon as it is instantiated. – paul_f Jan 29 '19 at 09:38