session.dataTaskWithURL completionHandler never called
The task never completes because it never gets started. You have to manually start the data task using its resume()
method.
let urlPath = apiURL + apiVersion + url + "?api_key=" + apiKey
let url = NSURL(string: urlPath)!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { data, response, error in
print("Task completed")
// rest of the function...
}
task.resume()
Why doesn't NSURLSession.dataTaskWithURL() call my completion handler?
You forgot to call resume()
.
let session:NSURLSession = NSURLSession(configuration: sessionConfig)
let task = session.dataTaskWithURL(actualUrl, completionHandler: {
(data:NSData?, response:NSURLResponse?, error:NSError?) in
NSLog("Got data = \(data)")
NSLog("Got response = \(response)")
NSLog("Got error = \(error)")
self.searchResults = data
self.delegate?.searchResultsAreReady()
})
task.resume() // you miss this
NSURLSessionDataTask completion handler not executing in command line project
A command line interface does not have a runloop by default so asynchronous tasks cannot work.
You have to start and stop the runloop explicitly
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
CFRunLoopRef runloop = CFRunLoopGetCurrent();
NSURLSession* session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:@"https://itunes.apple.com/search?term=apple&media=software"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"%@", json);
CFRunLoopStop(runloop);
}];
[dataTask resume];
CFRunLoopRun();
}
return 0;
}
You should handle the dataTask
error to exit with a value != 0
NSURLSessionDataTask dataTaskWithURL completion handler not getting called
If you're going to use the completion block rendition of the data task, rather than specifying a delegate
of nil
, like this:
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject
delegate: nil
delegateQueue: [NSOperationQueue mainQueue]];
You should instead instantiate your session using the method that does not take a delegate
at all:
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject];
Or, alternatively, given that you're not customizing your configuration at all, you can skip the instantiation of the NSURLSessionConfiguration
altogether and use the shared NSURLSession
:
NSURLSession *defaultSession = [NSURLSession sharedSession];
But, bottom line, you should not use the sessionWithConfiguration:delegate:queue:
rendition unless you're going to implement the delegates, in which case you wouldn't use the rendition of the NSURLSessionDataTask
method with the completionHandler
parameter.
Also, make sure your device/simulator is running iOS 7.0 or greater.
NSURLSessionDataTask completion handler block is not called
completionHandler won't get executed immediately, just like how the name sounds it will be executed only after the task is completed.
So its normal behavior to not execute the completionHandler immediately and go to the next line.
NSURLSession completion block not called
So I tried calling it like this
session.dataTaskWithRequest(urlRequest,
completionHandler: {(data: NSData!,
response: NSURLResponse!,
error: NSError!) in
print(data)
print(response)
print(error)
}).resume()
And it worked.
Seems like I have to call resume()
on a default suspended session task.
data with request completionhandler not always called
I tried to fix your code and explain with some comments:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let selectedMovieId = self.IDs[indexPath.row]
chosenMovieId = selectedMovieId
self.movieInfoFrom(searchMovie: chosenMovieId)
}
// Preparations before going to the detail view of selected movie
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
let destinationVC = segue.destinationViewController as! MovieDetailController
destinationVC.movieDetails = self.infoResult
destinationVC.moviePoster = poster
}
}
func movieInfoFrom(searchMovie movieId: String) {
let movieUrlString = "http://www.omdbapi.com/?i=\(movieId)&y=&plot=full&r=json"
let url = NSURL(string: movieUrlString)
print(movieUrlString)
let urlRequest = NSURLRequest(URL: url!)
let urlSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
// This is asynchronously, you can put a loading here
let urlTask = urlSession.dataTaskWithRequest(urlRequest) { (data, response, error) in
// Got response, stop loading here
if error == nil {
// Convert data to JSON
let swiftyJSON = JSON(data: data!)
let title = swiftyJSON["Title"].string!
let runTime = swiftyJSON["Runtime"].string!
let genre = swiftyJSON["Genre"].string!
let plot = swiftyJSON["Plot"].string!
let rating = swiftyJSON["imdbRating"].string!
let year = swiftyJSON["Year"].string!
// You can save the poster as local variable
let poster = swiftyJSON["Poster"].string
self.infoResult = ["\(title)", "\(runTime)", "\(genre)", "\(plot)", "\(rating)", "\(year)"]
print("\(self.infoResult)")
// This should be call on main thread
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("showDetail", sender: self)
}
}
}
urlTask.resume()
}
NSURLSessionDataTask not executing the completion handler block
NSURLSessionDataTask
runs in a background thread. To update anything in the user interface such as labels, buttons, table views, etc, you must do so on the main thread. If you want to update the label text from the completionHandler
block then you need to update the label in the main thread like so:
dispatch_sync(dispatch_get_main_queue(), ^{
nameLabel.text = @"yay!";
});
Related Topics
Use Multiple Codingkeys for a Single Property
How to Implement iOServicematchingcallback in Swift
How to Access Firebase Variable Outside Firebase Function
How Do Generators Whose Element Is Optional Know When They'Ve Reached the End
Arkit -Drop a Shadow of 3D Object on the Plane Surface
Swift 5 Table View Cell with Uiimage Appears Very Tall and Image Extremely Zoomed
Swift Test Give Error "Undefined Symbols for Architecture X86_64"
How to Save Document to "Files" App in Swift
Why Does Swiftui Uihostingcontroller Have Extra Spacing
How to Generate Random Numbers Without Repetition in Swift
Swift 3 String Contains Exact Sentence/Word
Swiftui: How to Make Entire Shape Recognize Gestures When Stroked
Executing Text-To-Speech in Order
Any Way to Chain == and || Operands