iOS 9 Best solution for parsing JSON - ios

I always used this solution when I needed to parse a feed JSON.
https://stackoverflow.com/a/20077594/2829111
But sendAsynchronousRequest is now deprecated and I'm stuck with this code
__block NSDictionary *json;
[[session dataTaskWithURL:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// handle response
json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"Async JSON: %#", json);
[collectionView reloadData];
}] resume];
And with this the reloadData argument takes a long time to execute. I've alredy tried forcing back to the main queue with:
__block NSDictionary *json;
[[session dataTaskWithURL:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// handle response
json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"Async JSON: %#", json);
dispatch_sync(dispatch_queue_create("com.foo.samplequeue", NULL), ^{[collectionView reloadData});
}] resume];

The problem is that the completion handler does not run on the main queue. But all UI updates must happen on the main queue. So dispatch that to the main queue:
[[session dataTaskWithURL:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// handle response
NSError *parseError;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
// do something with `json`
dispatch_async(dispatch_get_main_queue()), ^{[collectionView reloadData]});
}] resume];

Why don't you try JSONModel library....... it is so simple to use
-(void)getEmployeePerformance:(EmpPerformanceRequest*)request
withSuccesBlock:(succesEmployeePerformanceResponseBlock) successBlock
andFailBlock:(FailResponseBlock) failBlock
{
NSString* weatherUrl = [[ABWebServiceUtil sharedInstance]getEmployeePerformanceURL];
[HTTPClientUtil postDataToWS:weatherUrl parameters:[request toDictionary] WithHeaderDict:nil withBlock:^(AFHTTPRequestOperation *responseObj, NSError *error)
{
if(responseObj.response.statusCode == HTTP_RESPONSE_SUCESS)
{
EmpPerformanceArrayModel *empPerfArrModel;
if(responseObj.responseString)
{
empPerfArrModel = [[EmpPerformanceArrayModel alloc]initWithString:result error:nil];
empPerfArrModel.employeesArray = [empPerformanceModel arrayOfModelsFromDictionaries:empPerfArrModel.employeesArray];
}
if(successBlock)
{
successBlock(responseObj.response.statusCode, empPerfArrModel);
}
}else if (failBlock)
{
failBlock(responseObj.response.statusCode);
}
}];
}
for more detail follow this link...... it will brief you well
https://github.com/icanzilb/JSONModel

Try parsing JSON in connectionDidFinishLoading so you will get response as NSDictionary.
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
Class NSJSONSerializationclass = NSClassFromString(#"NSJSONSerialization");
NSDictionary *result;
NSError *error;
if (NSJSONSerializationclass)
{
result = [NSJSONSerialization JSONObjectWithData: responseData options: NSJSONReadingMutableContainers error: &error];
}
// If the webservice response having values we have to call the completionBlockā€¦
if (result)
{
if (self.completionBlock != nil)
{
self.completionBlock(result);
}
}
}

Related

Wait for Asynchronous request before execution of other code

I'am using [NSURLSession sharedSession] dataTaskWithRequest to get data from webserver and display it in a label & set button images according to it
But my problem is first label code is executed and they are displayed as empty then async block code is finished.
if(![self connected])
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
arrMyres = [[NSMutableArray alloc] initWithArray:[prefs objectForKey:#"Myres"]];
}
else
{
// POSTrequest with URL to get data from server
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:
^(NSData * _Nullable responseData,
NSURLResponse * _Nullable urlResponse,
NSError * _Nullable error) {
if (error) {
//Display error
}
else
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)urlResponse;
if([httpResponse statusCode ]>=200 && [httpResponse statusCode]<300)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
NSArray *array=[[dataDictionary objectForKey:#"GetExistingFavorites"] isKindOfClass:[NSNull class]]? nil:[dataDictionary objectForKey:#"GetExistingFavorites"];
arrMyres=[[NSMutableArray alloc]initWithArray:array];
});
}
}
}] resume];
}
//This block of code executes first and displays empty label
if([arrMyres count]>0 )
{
//Set Button Image and display label
}
else
{
// Do something else
}
How to wait for asynchrous request to complete execution and use it results somewhere after it? During research I found about dispatch groups and completion handlers. but couldnt understand how to implement
Any suggestions would be helpful.
Update firstLabel UI code inside of async code using main thread. Refer below code
if(![self connected])
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
arrMyres = [[NSMutableArray alloc] initWithArray:[prefs objectForKey:#"Myres"]];
[self updateUI];
}
else
{
// POSTrequest with URL to get data from server
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:
^(NSData * _Nullable responseData,
NSURLResponse * _Nullable urlResponse,
NSError * _Nullable error) {
if (error) {
//Display error
}
else
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)urlResponse;
if([httpResponse statusCode ]>=200 && [httpResponse statusCode]<300)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error];
NSArray *array=[[dataDictionary objectForKey:#"GetExistingFavorites"] isKindOfClass:[NSNull class]]? nil:[dataDictionary objectForKey:#"GetExistingFavorites"];
arrMyres=[[NSMutableArray alloc]initWithArray:array];
//This block of code executes first and displays empty label
if([arrMyres count]>0 )
{
[self updateUI];
}
}
}
}] resume];
}
-(void)updateUI {
dispatch_async(dispatch_get_main_queue(), ^{
//update UI in main thread.
//Add your ui updates
});
}

iOS: <extracting data from value failed> when accessing NSDictionary

I'm implementing an rest call to server and parsing the JSON:
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"error: %#",error.description);
}
else{
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
completionBlock(json,error);
}
}];
But the problem is when I try to access the contents the NSDictionary using objectForKey:
(lldb) po [json objectForKey:#"images"]
<extracting data from value failed>
If I po json:
{
images = (
{
.
.
}
);
}
My question to you guys is why I'm getting this error?, or there is a way around this?
I'll really appreciate your help

Objective-C Return a String in NSURLSessionDataTask

I am trying to create a NSString function to return a string that has the NSURLSessionDataTask
- (NSString *) retrieveData
{
self.session = [NSURLSession sharedSession];
self.dataTask = [self.session dataTaskWithURL:[NSURL URLWithString:URL] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if(data)
{
self.json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
NSLog(#"%#", self.json);
for(NSDictionary *stateArray in self.json)
{
NSString *sName = stateArray[#"State"];
if(self.state == sName)
{
NSString *sFlag = stateArray[#"State_Flag_Path"];
return sFlag;
}
}
}
else
{
NSLog(#"Failed to fetch URL: %#", error);
}
}];
[self.dataTask resume];
}
Then, I get an error message for incompatible block pointer types issue.
Can anyone please help?
Thank you in advance.
I found a way...
return the string after
[self.dataTask resume];

Execute task after another

Recently I started developing for iOS and faced problem which is maybe obvious for you but I couldn't figure it out by myself.
What I'm trying to do is to execute task after another one, using multithreading provided by GCD.
This is my code for fetching JSON (put in class with singleton)
CategoriesStore
- (instancetype)initPrivate {
self = [super init];
if (self) {
[self sessionConf];
NSURLSessionDataTask *getCategories =
[self.session dataTaskWithURL:categoriesURL
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
if (error) {
NSLog(#"error - %#",error.localizedDescription);
}
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *) response;
if (httpResp.statusCode == 200) {
NSError *jsonError;
NSArray *json =
[NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:&jsonError];
if (!jsonError) {
_allCategories = json;
NSLog(#"allcategories - %#",_allCategories);
}
}
}];
[getCategories resume];
}
return self;
}
Then in ViewController I execute
- (void)fetchCategories {
NSLog(#"before");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
CategoriesStore *categories = [CategoriesStore sharedStore];
dispatch_async(dispatch_get_main_queue(), ^(void) {
_allDirectories = categories.allCategories;
[self.tableView reloadData];
NSLog(#"after");
});
});
}
-fetchCategories is executed in viewDidAppear. The result is usually before, after and then JSON. Obviously what I want to get is before, json after.
I also tried to do this with dispatch_group_notify but didn't workd.
How can I get it working? Why it doesn't wait for first task to be finished?
Thank's for any help!
Regards, Adrian.
I would suggest to define a dedicated method in CategoriesStore that fetches data from remote server and takes callback as an argument:
- (void)fetchDataWithCallback:(void(^)(NSArray *allCategories, NSError* error))callback
{
NSURLSessionDataTask *getCategories =
[self.session dataTaskWithURL:categoriesURL
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
if (error) {
NSLog(#"error - %#",error.localizedDescription);
callback(nil, error);
return;
}
NSError *jsonError = nil;
NSArray *json =
[NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:&jsonError];
if (!jsonError) {
_allCategories = json;
NSLog(#"allcategories - %#",_allCategories);
callback(_allCategories, nil);
} else {
callback(nil, jsonError);
}
}];
[getCategories resume];
}
And you can use it in your ViewController:
- (void)fetchCategories {
[[CategoriesStore sharedStore] fetchDataWithCallback:^(NSArray *allCategories, NSError* error) {
if (error) {
// handle error here
} else {
_allDirectories = allCategories;
[self.tableView reloadData];
}
}]
}
In this way you will reload your table view after data loading & parsing.
You have to wait for the reload data so you may do something like this, another option if you don't want to wait for the whole block and just for the fetch is to use a custom NSLock
dispatch_sync(dispatch_get_main_queue(), {
_allDirectories = categories.allCategories;
[self.tableView reloadData];
}
NSLog(#"after");
I used method suggested by #sgl0v, although it wasn't solution I expected.
Another way to do this is by using notification center and listening for event to occur.

Multiple web service calls at the same time in iOS

In my app i need to call two services at a time. for single service i am using the below code:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
// Instantiate a session object.
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURL *url = [NSURL URLWithString:#"my link"];
// Create a data task object to perform the data downloading.
NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error != nil) {
// If any error occurs then just display its description on the console.
NSLog(#"%#", [error localizedDescription]);
}
else{
// If no error occurs, check the HTTP status code.
NSInteger HTTPStatusCode = [(NSHTTPURLResponse *)response statusCode];
// If it's other than 200, then show it on the console.
if (HTTPStatusCode != 200) {
NSLog(#"HTTP status code = %d", (int)HTTPStatusCode);
} else {
NSMutableArray *jsonData = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves error:nil];
NSLog(#"json data ==========> %#", jsonData);
}
}
}];
// Resume the task.
[task resume];
by using this i am getting the data. Now, at the same time i need to call another service. How can i achieve this? and How i will get the data?

Resources