It looks like I didn't get the concept of blocks completely yet...
In my code I have to get out the JSON data from the asychronous block
to be returned to from the 'outer
' method. I googled and found that if defining a variable with __block
, the v̶i̶s̶i̶b̶i̶l̶i̶t̶y̶ _mutability_ of
that variable is extended to the block
.
But for some reason returned json object is nil.I wonder why?
- (NSMutableDictionary *)executeRequestUrlString:(NSString *)urlString
{
__block NSMutableDictionary *json = nil;
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPShouldHandleCookies:YES];
[request setHTTPMethod:@"GET"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-type"];
NSString *cookieString = [self.userDefaults objectForKey:SAVED_COOKIE];
[request addValue:cookieString forHTTPHeaderField:@"Cookie"];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSLog(@"dataAsString %@", [NSString stringWithUTF8String:[data bytes]]);
NSError *error1;
NSMutableDictionary * innerJson = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&error1];
json = innerJson;
}];
return json;
}
First, to answer your question:
But for some reason returned json object is nil
. I wonder why?
The variable that you are returning has not been set at the time when you return it. You cannot harvest the results immediately after the sendAsynchronousRequest:queue:completionHandler:
method has returned: the call has to finish the roundtrip before calling back your block and setting json
variable.
Now a quick note on what to do about it: your method is attempting to convert an asynchronous call into a synchronous one. Try to keep it asynchronous if you can. Rather than expecting a method that returns a NSMutableDictionary*
, make a method that takes a block of its own, and pass the dictionary to that block when the sendAsynchronousRequest:
method completes:
- (void)executeRequestUrlString:(NSString *)urlString withBlock:(void (^)(NSDictionary *jsonData))block {
// Prepare for the call
...
// Make the call
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSLog(@"dataAsString %@", [NSString stringWithUTF8String:[data bytes]]);
NSError *error1;
NSMutableDictionary * innerJson = [NSJSONSerialization
JSONObjectWithData:data options:kNilOptions error:&error1
];
block(innerJson); // Call back the block passed into your method
}];
}
When you call sendAsynchronousRequest:queue:completionHandler:
, you've requested an asynchronous request. So it queues the request and the block and returns immediately. At some point in the future the request is made, and some point after that the completion block is run. But by that time, return json
has long since run.
If you want to be able to return the data synchronously, then you must make a synchronous request. That will hang this thread until it completes, so it must not be the main thread.
Check the string when converting data coming from server using below code:
NSLog(@"dataAsString %@", [NSString stringWithUTF8String:[data bytes]]);
if the string is in a proper JSON format, ONLY then your JSON object will be correct.
Hope this hepls!!