Session.Datataskwithurl Completionhandler Never Called

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



Leave a reply



Submit