How to get data to return from NSURLSessionDataTask
The post completes asynchronously, so your wsClass
needs to tell the caller about completion after post is finished. A nice way to do this is to augment the sendData
method with a block of code supplied by the caller that should be run upon completion:
Change sendData:
to look like this:
// it doesn't return anything, because all it does is launch the post
// but when the post is done, it invokes completion
- (void)sendData:(NSDictionary *)sendDict completion:(void (^)(NSDictionary *))completion {
// the stuff you're already doing
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// the stuff you're already doing
// now tell the caller that you're done
completion(jsonArray);
}];
}
The caller now looks like this:
// change the UI to say "I'm busy doing the post"
[ws sendData:testDict completion:^(NSDictionary *responseDict) {
NSLog(@"this runs later, after the post completes %@", responseDict);
// change the UI to say "The post is done"
}];
Just a couple of notes about this: (1) I didn't add an error param to the block, you probably should. Check that and invoke the block with either nil and an error, or with the json output and error=nil. (2) Your code assumes that the json result parses as a dictionary. Make sure that's always true before you assume it in code. (3) Class names usually begin with caps.
How to get data to return from NSURLSessionDataTask in Swift
With the help and suggestion taken from Abizern I finally managed how to write up this block or closure if you want.
So what worked for me in the end:
The GetHomeData function I changed as follows:
private let siteContent:String = "http://www.imoc.co.nz/MobileApp/HomeContent"
// I changed the signiture from my original question
func GetHomeData(completionHandler: ((NSDictionary!) -> Void)?)
{
var url : NSURL! = NSURL(string:siteContent)
var request: NSURLRequest = NSURLRequest(URL:url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: error) as? NSDictionary!
// then on complete I call the completionHandler...
completionHandler?(jsonResult?);
});
task.resume()
}
Then I call the function like this:
/*Call to go get home page content*/
func SetHomeContent()
{
homeModel.GetHomeData(self.resultHandler)
}
func resultHandler(jsonResult:NSDictionary!)
{
let siteContent = jsonResult.objectForKey("SiteContent") as NSDictionary
let paraOne = siteContent.objectForKey("HomePageParagraphOne") as String
}
NSURLSessionDataTask return data in completion handler, Swift 2.0
In your current function definition type of completionHandler
is optional String, it's not a function. If you want completionHandler
to be a function that you call when data task finishes, change function definition to func getConfigurationLink(completionHandler: String? -> ())
. So here completionHandler
is a function that takes an optional String as parameter.
You can read on how to pass a function as a parameter type for another function (that's what you're trying to do here, you're passing completionHandler
function to getConfigurationLink
and then calling completionHandler
when network request completes) here: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html#//apple_ref/doc/uid/TP40014097-CH10-ID166
And a little more explanation about compeletionHandlers: https://thatthinginswift.com/completion-handlers/
You can call getConfigurationLink
using closure like this:
getConfigurationLink { (str: String?) in
// you can use str here
}
Here is more info on closures: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html
How can I get the Data from NSURLSession.sharedSession().dataTaskWithRequest
You can't return data directly from an asynchronous task.
The solution with Swift 2 is to make a completion handler like this:
class PostFOrData {
// the completion closure signature is (NSString) -> ()
func forData(completion: (NSString) -> ()) {
if let url = NSURL(string: "http://210.61.209.194:8088/SmarttvWebServiceTopmsoApi/GetReadlist") {
let request = NSMutableURLRequest( URL: url)
request.HTTPMethod = "POST"
let postString : String = "uid=59"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if let data = data,
jsonString = NSString(data: data, encoding: NSUTF8StringEncoding)
where error == nil {
completion(jsonString)
} else {
print("error=\(error!.localizedDescription)")
}
}
task.resume()
}
}
}
let pfd = PostFOrData()
// you call the method with a trailing closure
pfd.forData { jsonString in
// and here you get the "returned" value from the asynchronous task
print(jsonString)
}
That way, the completion is only called when the asynchronous task is completed. It is a way to "return" the data without actually using return
.
Swift 3 version
class PostFOrData {
// the completion closure signature is (String) -> ()
func forData(completion: @escaping (String) -> ()) {
if let url = URL(string: "http://210.61.209.194:8088/SmarttvWebServiceTopmsoApi/GetReadlist") {
var request = URLRequest(url: url)
request.httpMethod = "POST"
let postString : String = "uid=59"
request.httpBody = postString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request) {
data, response, error in
if let data = data, let jsonString = String(data: data, encoding: String.Encoding.utf8), error == nil {
completion(jsonString)
} else {
print("error=\(error!.localizedDescription)")
}
}
task.resume()
}
}
}
let pfd = PostFOrData()
// you call the method with a trailing closure
pfd.forData { jsonString in
// and here you get the "returned" value from the asynchronous task
print(jsonString)
}
Swift - Return data from NSURLSession when sending POST request
Your post function might be like:
func post(completionHandler: (response: String) -> ()) { your code }
And in the response part:
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
completionHandler(response: responseString)
Finally, you can call your post method like:
post( {(response: String) -> () in
println("response = \(response)")})
How to get data from blocks using NSURLSession?
-(void)getJsonResponse:(NSString *)urlStr success:(void (^)(NSDictionary *responseDict))success failure:(void(^)(NSError* error))failure
{
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:urlStr];
// Asynchronously API is hit here
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"%@",data);
if (error)
failure(error);
else {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"%@",json);
success(json);
}
}];
[dataTask resume]; // Executed First
}
call this:
[self getJsonResponse:@"Enter your url here" success:^(NSDictionary *responseDict) {
NSLog(@"%@",responseDict);
} failure:^(NSError *error) {
// error handling here ...
}];
Related Topics
Msmessagelivelayout Freeze/Crash in Transcript When Info.Plist Contains Privacy Request
How to Create Travelling Wave in Spritekit
Sprite Kit Game Crashes on Game Over on Tvos 9.1 and iOS 9.2
Could Not Find an Overload for '-' That Accepts The Supplied Arguments
Swift: Reflection of Protocol Variables
Swiching Between 2 Diferent Nsviewcontrollers with Data
Replicate Opengl Blending in Metal
Uisearchcontroller Hiding Status Bar on iOS 11 Swift 4
Multiple Enum Implementing Protocols Questions
Nssavepannel - How to Restrict User to Only Save One One Set Directory
Scan for Ble Devices and Present Them in an UItableview
How to Resolve Rctpromiseresolveblock After Bftask
Is There Any Shorthand Way to Write Cgpoint, Cgrect, etc
Touch Sprite, Make It Jump Up Then Fall Down Again(Repeat as Many Times as Spritenode Is Tapped.)
Optional in Swift, Return Count of Array
Nstimer Scheduledtimerwithtimeinterval and Target Is "Class Level Function"