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

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

Related

iOS 9 Best solution for parsing JSON

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);
}
}
}

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.

How can I parse this JSON information?

Here is what I want to parse.
{
"Words": {
"subjugate": "To conquer. ",
"contemplate": "To consider thoughtfully. ",
"comprise": "To consist of. ",
"pollute": "To contaminate. "
}
}
Here is a very stripped and over-simplified way to handle getting response data back from a server in JSON and serializing the JSON to an NSDictionary:
// this is just for example purposes, in this example the code is already running on a background thread so sending it synhcronously is OK, and I've already created the request object
NSError *error = nil;
NSHTTPURLResponse *response = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// if we don't have response data
if (!responseData) {
// handle that we got no response from the server
}
if (error) {
// handle the request error
}
// serialize the JSON result into a dictionary
NSError *serializationError = nil;
NSDictionary *resultDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:0 &serializationError];
if (serializationError) {
// handle the error turning the data into dictionary
}
NSDictionary *wordsDictionary = resultDictionary[#"words"];
NSString *exampleValue = wordsDictionary[#"subjugate"]; // will be "To conquer." if everything goes to plan
You can parse as bellow
NSData *data = [#"{\"Words\":{\"subjugate\":\"To conquer.\",\"contemplate\":\"To consider thoughtfully.\",\"comprise\":\"To consist of.\",\"pollute\":\"To contaminate.\"}}" dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
if(error)
{
NSLog(#"Error : %#", error);
}
else
{
NSLog(#"%#", json);
}

Cannot parsing Json to NSDictionary

I have a WebService, which give me the fallowing Json-String back:
"{\"password\" : \"1234\", \"user\" : \"andreas\"}"
I call the webservice and try to parse the returned data like:
[NSURLConnection sendAsynchronousRequest: request
queue: queue
completionHandler: ^(NSURLResponse *response, NSData *data, NSError *error) {
if (error || !data) {
// Handle the error
} else {
// Handle the success
NSError *errorJson = nil;
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &errorJson];
NSString *usr = [responseDict objectForKey:#"user"];
}
}
];
But the resulting NSDictionary looks like:
What has the effect, that I cannot get the values - for example user.
Can someone help me, what I am doing wrong? - Thank you.
From the debugger screenshot is seems that the server is (for whatever reason) returning
"nested JSON": responseDict[#"d"] is a string containing JSON data again, so you have to
apply NSJSONSerialization twice:
NSError *errorJson = nil;
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData: data options:0 error: &errorJson];
NSData *innerJson = [responseDict[#"d"] dataUsingEncoding:NSUTF8StringEncoding];
NSMutableDictionary *innerObject = [NSJSONSerialization JSONObjectWithData:innerJson options:NSJSONReadingMutableContainers error:&errorJson];
NSString *usr = [innerObject objectForKey:#"user"];
If you have the option, a better solution would be to fix the web service to return
proper JSON data.

Resources