I have an app that downloads some information from a URL (ie. author name, story title, and the cover image). I'm able to download and parse the JSON from the server properly, but I'm stuck at one point.
The app consists of one View Controller (called ViewController.swift) and one class file (called GetStories.swift). Once the app has finished download and parsing the JSON from the server, I want the table view in the View Controller to reload itself (self.tableView.reloadData()).
I've set up a chain of completion blocks in GetStories.swift that accomplish the following steps in order: 1) Download the JSON 2) Parse the JSON 3) Save it to disk
func updateUI(){
saveDownloadedAndParsedJSONToDisk {
}
}
func saveDownloadedAndParsedJSONToDisk(completionHandler: @escaping RefreshTableView){
parseJSON {
self.saveDataToJSON()
completionHandler()
}
}
func parseJSON(completionHandler: @escaping ReadyToSave){
downloadJSON { jsonPayload, error in
do {
if let data = jsonPayload {
self.stories = try JSONDecoder().decode(Stories.self, from: data)
if let stories = self.stories {
self.stories = stories
completionHandler()
} else {
print("An error occurred while decoding JSON.")
}
} else if let error = error {
print("Error retrieving data: \(error)")
}
} catch {
print(error.localizedDescription)
}
}
}
func downloadJSON(completionHandler: @escaping NetworkResponse){
let storiesAPIURL = URL(string: "\(wattpadAPIURL)")
var wattpadAPIRequest = URLRequest(url: storiesAPIURL!)
wattpadAPIRequest.httpMethod = "GET"
let session = URLSession.shared
let dataTask = session.dataTask(with: wattpadAPIRequest) { (data : Data?, response : URLResponse?, error : Error?) in
if let data = data {
completionHandler(data, nil)
} else if let error = error {
completionHandler(nil, error)
print(error.localizedDescription)
}
}
dataTask.resume()
}
In ViewController.swift, I am calling updateUI(). Then, I'm calling the delegate method in the protocol:
self.storyResults?.delegate?.didFinishFetchingAndParsingData(finished: true)
The delegate method is doing this:
func didFinishFetchingAndParsingData(finished: Bool) {
guard finished else {
return
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.tableView.reloadData()
SVProgressHUD.dismiss()
}
}
So, as you see, I'm using a 0.5 second delay to reload the table view because I'm not sure how to tell when exactly the downloading, parsing and saving has all fully finished.
If I don't use the delay of 0.5 seconds in the delegate method, the table view gets reloaded at an inappropriate time and there are no results displayed as a result. So, executing the reload this way doesn't work:
DispatchQueue.main.async {
self.tableView.reloadData()
}
What is the proper way to do this?
Thanks in advance!