You can't - and shouldn't - wait until an async call to complete. You need to study async programming until you understand it.
An async function accepts a job to do, and returns immediately, before the job is done.
in Swift you usually write an async function to take a completion handler, which is a block of code that you want to be run one the async task is complete.
I have a project called Async_demo (link) on Github that illustrates this. It implements a DownloadManager class that handles async downloads.
The key part is the function downloadFileAtURL()
, which should more properly be named downloadDataAtURL, since it returns in-memory data rather than a file.
I created that function to take a completion handler as a parameter:
/**
This function demonstrates handling an async task.
- Parameter url The url to download
- Parameter completion: A completion handler to execute once the download is finished
*/
func downloadFileAtURL(_ url: URL, completion: @escaping DataClosure) {
//We create a URLRequest that does not allow caching so you can see the download take place
let request = URLRequest(url: url,
cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 30.0)
let dataTask = URLSession.shared.dataTask(with: request) {
//------------------------------------------
//This is the completion handler, which runs LATER,
//after downloadFileAtURL has returned.
data, response, error in
//Perform the completion handler on the main thread
DispatchQueue.main.async() {
//Call the copmletion handler that was passed to us
completion(data, error)
}
//------------------------------------------
}
dataTask.resume()
//When we get here the data task will NOT have completed yet!
}
}
It uses an NSURLSession to download a block of data from the specified URL. The data request call I use takes a completion handler that gets executed on a background thread. In the completion handler that I pass to the data task, I invoke the completion handler that's passed in to the downloadFileAtURL()
function, but on the main thread.
The code you posted is kind of confusing. It isn't clear which part is the async function, what the flow is, or what data is needed to display your table view.
If you rewrite your function that does async work to take a completion block then you could call tableView.reloadData()
in your completion block. (Make sure that call is performed on the main thread.)
EDIT:
As others have said, you need to edit your question to show the code for your fetchItems()
function.
I'm guessing that that function is the one that does the Async work, and that the block after it is a completion handler that gets performed asynchronously. If so, you should probably refactor your code like this:
var functionResult = [String]()
override func viewDidLoad() {
super.viewDidLoad()
//I moved these lines above the call to fetchItems to make it clear
//that they run before fetchItems' completion closure is executed
self.tableofItems.delegate = self
self.tableofItems.dataSource = self //Data source is set up to use functionResult, however functionResult is empty before fetchItem runs.
print("Step 1")
fetchItems{ (str) in
var returnedItems = [String]()
let result = self.convertoArray(itemstoPass: str!)
for i in result{
functionResult.append(i)
}
print("Step 3")
DispatchQueue.main.async() {
tableview.reloadData() //Do this from the main thread, inside the closure of `fetchItems()`
}
}
print("Step 2")
}