Wait for download task to finish in NSURLSession
As I said before in the comments of the main post the download NSURLSession.sharedSession().dataTaskWithRequest(request)
run synchronously to the main thread which means it downloads the data synchronously to the displaying. So in short the print("test0")
will be executed when the dispatched thread is finished (aka downloaded the data). To fix this I had to use semaphores (I also combined the first code and the second code from the original question):
private func downloadData(completion: (String) -> ()) {
let semaphore = dispatch_semaphore_create(0);
let request = NSMutableURLRequest(URL: url)
var theJSONData = NSData()
do {
theJSONData = try NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions())
} catch {
completion(String())
}
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.HTTPBody = theJSONData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
data == nil ? completion(String()) : completion(String(data: data!, encoding: NSUTF8StringEncoding)!)
dispatch_semaphore_signal(semaphore);
}
task.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
This may not be the most efficient nor the most elegant solution but in my case I really had to wait for the downloading to be finished else it shouldn't do anything.
How to wait for all tasks of an NSURLSession to complete?
I found a solution that avoids invalidating the session, using the suggested DispatchGroup
.
(answer is in Swift, while question is in ObjC ... but it's the same logic)
Note that when using, uploadTaskWithStreamedRequest:
, we need to implement an URLSessionTaskDelegate
and func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
. So, to simplify the answer, I will demonstrate the use of DispatchGroup
with uploadTaskWithRequest:from:completionHandler:
.
// strong reference to the dispatch group
let dispatchGroup = DispatchGroup()
func performManyThings() {
for _ in 1...3 {
let request = URLRequest(url: URL(string: "http://example.com")!)
dispatchGroup.enter()
let uploadTask = self.session.uploadTask(with: request, from: nil) { [weak self] _, _, _ in
self?.dispatchGroup.leave()
}
uploadTask.resume()
}
dispatchGroup.notify(queue: .main) {
// here, all the tasks are completed
}
}
Function does not wait until the data is downloaded
The other answer is not a good replacement for the code you already had. A better way would be to continue using NSURLSession's data tasks to keep the download operation asynchronous and adding your own callback block to the method. You need to understand that the contents of the download task's block are not executed before you return from your method. Just look at where the call to resume() is for further evidence.
Instead, I recommend something like this:
func getImageFromServerById(imageId: String, completion: ((image: UIImage?) -> Void)) {
let url:String = "https://dummyUrl.com/\(imageId).jpg"
let task = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) {(data, response, error) in
completion(image: UIImage(data: data))
}
task.resume()
}
Which can be called like this
getImageFromServerById("some string") { image in
dispatch_async(dispatch_get_main_queue()) {
// go to something on the main thread with the image like setting to UIImageView
}
}
Related Topics
Naming Convention for Private Properties
Swift Display Image UIimageview
Avspeechrecognizer: Required Condition Is False: _Recordingtap == Nil Error in Swift3
How to Detect If The User Was Deleted from Firebase Auth
Get Output Frames Failed, State 8196
Show and Hide Window Instead of Terminating App on Close Click in Cocoa App
How to Write to a Variable from Within The Firebase Getdocument Function (Swift)
The #Selector Is Not Compatible with The Closure
How to Create a Single Page Vertical Scrolling Pdfview in Swift
Swift Error: Failed to Get Module 'My_App' from Ast Context
Why Is Inceptionv3 Machine Learning Model Not Recognized on My Project
Swift Combine How Set<Anycancellable> Works
Ambiguous Reference to Member 'Buildblock()'
Navigation Link in Bar Items Goes Back to Top of Navigationview
iOS App Extension - Action - Custom Data
Error: 'string' Is Not Convertible to 'string!'
How to Access The Model Component of Reality Composer in Realitykit