How to get rid of multiple sets of parentheses in an array - ios

I'm using RESTKit to do some object mapping for a JSON and I'm mapping an array. The JSON that I'm mapping looks like this: "parameters":[{"parameter_value":["Smith"]}, {"parameter_value":[66211]}]
The array that I'm getting looks like this:
Parameter Value: (
(
Smith
),
(
66211
)
)
When I try to convert the array to a string via this code: NSString *nameidvalue = [[parameterValueArray valueForKey:#"description"] componentsJoinedByString:#""]; The string nameidvalue turns into this:
(
Smith
)(
66211
)
How exactly do I get rid of the parentheses so what I'm left with is Smith, 66211

You asked about eliminating "sets of parentheses", but given that the underlying structure is a series of nested collections (dictionaries and arrays), you can achieve the desired effect by effectively collapsing a level or two from that structure. You can do this with the KVC collection operator, #unionOfArrays, used in conjunction with valueForKeyPath. If you really want to do a string manipulation, we can do that, but it seems more logical to write code that renders a simple array, and then you can use componentsJoinedByString if you really want a simple string at the end.
What makes this answer a little complicated is that the reported JSON doesn't match the NSLog of the resulting NSDictionary, so I'm unclear as to precisely what the input was. So I'm going to show two permutations of this KVC collection operator, one that matches the provided sample JSON, and another that matches the JSON that I inferred from the NSDictionary structure you reported.
If the JSON is:
{"parameters":[{"parameter_value":["Smith"]}, {"parameter_value":[66211]}]}
You could then parse that as follows (I'm using the NSJSONReadingMutableContainers so that I can change the results; if you're not trying to change the array, but rather just extract the appropriate results, then you don't need to make it mutable; it's up to you):
NSMutableDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:&error];
That would yield a NSMutableDictionary structure would be:
{
parameters = (
{
"parameter_value" = (
Smith
);
},
{
"parameter_value" = (
66211
);
}
);
}
But you could replace parameters with:
dictionary[#"parameters"] = [dictionary[#"parameters"] valueForKeyPath:#"#unionOfArrays.parameter_value"];
Yielding:
{
parameters = (
Smith,
66211
);
}
But, if you had JSON like:
{"parameters":[["Smith"],[66211]]}
And if you parsed that with the same NSJSONSerialization as above, that would yield a dictionary like:
{
parameters = (
(
Smith
),
(
66211
)
);
}
And you could replace the parameters value using the KVC collection operator #unionOfArrays again, this time using self:
dictionary[#"parameters"] = [dictionary[#"parameters"] valueForKeyPath:#"#unionOfArrays.self"];
That would yield:
{
parameters = (
Smith,
66211
);
}
You asked:
How exactly do I get rid of the parentheses so what I'm left with is Smith, 66211
If you, literally, just want #"Smith, 66211", you could then just take this simplified array and now use componentsJoinedByString:
NSString *string = [dictionary[#"parameters"] componentsJoinedByString:#", "];

Try
NSString *nameidvalue = [[parameterValueArray valueForKey:#"parameters"] componentsJoinedByString:#""];

Replace with,
NSString *nameidvalue = [[parameterValueArray valueForKey:#"description"] componentsJoinedByString:#","];

Try like.. Access the Objectforkey of Parameter Value and store into a dicitonary and then access the objectforkey of Smith and store the value into a string.
NSError *e = nil;
NSMutableArray *JSON = [NSJSONSerialization JSONObjectWithData: data options: NSJSONReadingMutableContainers error: &e];
NSDictionary *value = [JSON objectforkey:#"parameter_value"];
You will get the expected values.

Related

Concatenate Strings for Dictionary:syntax error

The following code to conditionally concatenate strings for a dictionary seems to work up to the point where I try to place the concatenated result in the dictionary. Can anyone see the error?
NSDictionary *jsonDictionary;
NSString* dictString = #"#\"first\":first,#\"last"
NSString *dictString2=dictString;
if (date.length>0&&![date isKindOfClass:[NSNull class]]) {
//only include this key value pair if the value is not missing
dictString2 = [NSString stringWithFormat:#"%#%s", dictString, "#\"date\":date"];
}
jsonDictionary = #{dictString2}; //syntax error. Says expected colon but that does not fix anything
The syntax for creating an NSDictionary using object literals is:
dictionary = #{key:value}
(and optionally, it can contain multiple key/value pairs separated by commas, but never mind that right now.)
Where "key" and "value" are both NSObjects.
Your line that is throwing the error only contains 1 thing. The contents of a the string in dictString2 has nothing to do with it.
It looks to me like you are trying to build a JSON string manually. Don't do that. Use NSJSONSerialization. That class has a method dataWithJSONObject that takes an NSObject as input and returns NSData containing the JSON string. That's how you should be creating JSON output.
Creating an NSDictionary with values that may be null:
NSDictionary *dict = #{
#"key" : value ?: [NSNull null],
};
When serializing a dictionary, NSNulls are translated to null in the JSON.
If you want to exclude such keys completely, instead of having them with a null value, you'll have to do more work. The simplest is to use an NSMutableDictionary and test each value before adding it.

objc How do I get the string object from this Json array?

This is part of an incoming array:
variantArray: (
(
{
CardinalDirection = "North-West";
DirectionVariantId = "DcCi_1445_171_0_0";
Distance = "2.516606318971459";
RouteName = "Woodsy";
Shape = {
Points = (
{
I want to get the value of DirectionVariantId
I would normally loop and use
NSMutableArray *myString = [variantArray[i] valueForKey:#"DirectionVariantId"];
This isn't working and results in an exception when I try to examine the last character in the string:
NSString *lastChar = [myString substringFromIndex:[myString length] - 1];
This is a new data set for me and I'm missing something..
Thanks for any tips.
Json contain two curly bracket means nested array.
Try:
NSString *myString=[[[variantArray objectAtIndex:0] objectAtIndex:0] objectForKey:#"DirectionVariantId"];
I think you're looking for [variantArray[i] objectForKey:#"DirectionVariantId"];
You'd need to convert the object within your incoming array (variantArray[i]) to a NSDictionary but it might already be judging by your original output.

iOS JSON Parsing, Format Issues

So I was working on a project that required me to work with some JSON, I was running into a few issues regarding the best way of representing things. First of, this is how the JSON looks:
"phoneList": [
{
"phoneReason": "End of Contract",
"phoneType": [
{
"id": 5,
"phoneType": "Android Smartphone"
}
]
}
]
I want to know the most appropriate way of representing this.
For example, I do know that that my phoneReason will just be a simple NSString while my phoneType is actually a NSArray. However,I wasn't sure how to represent a)the id, I know this is an integer, but should this be an NSInteger or an NSNumber and b)could someone point me in the direction of some sample code where I can understand how to model a dictionary object containing an integer and a string and also where I can understand how to model an array of dictionaries.
My other question is also similar in that say I'm actually posting something, how do I model this, specifically say for like dictionary type (JSON Curly Brace)objects that contain a number/integer and a string.
For example, this is the JSON I'm trying to model and then do something like this:
"phoneReason": "Upgrade",
"phoneInfo": {
"id": "2"
},
//And then I want to pass ID
-(void) createOurRequest:(NSNumber *)id {
NSDictionary *myDictionary = #{
#"phoneReason" : [NSString stringWithFormat:#"%i", s elf.dat.reason],
//How do I then represent the phoneInfo element exactly?
};
Sorry, for the clumsy question, would really appreciate any guidance on modeling JSON in iOS or just generally.
I'm assuming you're asking questions a) and b), and also how to model a JSON.
a) The unfortunate thing with Obj-C is that all collection elements have to be objects. Integers are value types, so they will need to be converted to NSNumbers to work. However, if you're parsing a JSON string, the builtin JSON parser does it for you. I'll describe it below.
b) The model is based on the JSON. You describe the object collection and the parser will determine the model for you. In your example, you would have a NSDictionary<NSString *: NSArray<NSDictionary<NSString *: id>*>*>. The innermost element has value of id because you can either have an NSString ("End of Contract") or an NSArray ("phoneType": [ { "id": 5, "phoneType": "Android Smartphone" } ])
Of course, the model is defined by your JSON, so if you run it through a parser, you get a structured object. You can access each element based on your model (object[#"phoneList"][#"phoneReason"]).
The class method to use is:
+ (id)JSONObjectWithData:(NSData *)data
options:(NSJSONReadingOptions)opt
error:(NSError **)error
Where you pass it a NSData representation of your string, options (or 0), and a NSError pointer (error*). You get back a parsed JSON with the proper structure you defined.
NSDictionary *parsedJSONObject = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:NULL
I have no options to use and I know there will be no error, so I pass nothing for those parameters. The resulting object will be in whatever structure your JSON is.
Using the objects and the json layout you provided in your first example, this is how I would go about creating the dictionaries and arrays to get the json in the format you specified. Hopefully this helps make it a little clearer for you.
// example constructor method
-(void) jsonStringWithPhoneReason:(NSString*)reason phoneId:(NSInteger)phoneId phoneType:(NSString*)phoneType
{
// create device detail dictionary
NSDictionary *deviceOneDetail = #{
#"id" : #(phoneId), // <- set phone id as NSNumber
#"phoneType" : phoneType // <- set your string phone type
};
// create device dictionary
NSDictionary *deviceOne = #{
#"phoneReason" : reason, // <- set your phone reason string
#"phoneType" : #[deviceOneDetail] // <- set your phone type dictionary within an array
};
// create phone list dictionary with any device dictionaries you want to add
NSDictionary *phoneListDict = #{
#"phoneList" : #[
deviceOne, // <- add your device to the phone list array of dictionaries
// deviceTwo...
]
};
NSString *jsonString = [self convertToJsonString:phoneListDict]; // <- convert the dictionary into a json string and use however you wish
// your json string should now look like this assuming you pass 'End of Contract', 5 & 'Android Smartphone' as arguments to this method
// {"phoneList":[{"phoneReason":"End of Contract","phoneType":[{"id":5,"phoneType":"Android Smartphone"}]}]}
}
-(NSString*) convertToJsonString:(NSDictionary*)dictionary
{
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary
options:0 // Pass 0 if you don't care about the readability of the generated string
error:&error];
if (error)
{
NSString *errorDesc = [NSString stringWithFormat:#"Error creating json data from dictionary: %#", error.localizedDescription];
NSLog(#"ERROR: %#", errorDesc);
jsonData = nil;
return nil;
}
NSString *returnString = nil;
if(jsonData != nil)
{
returnString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
return returnString;
}

How to convert a list to NSArray?

I keep getting this list which is stored as NSString:
(
"one",
two,
"three",
4
)
How do I convert the values into NSArray?
If you provide more information about where this list comes from or how it's made, maybe i can be of more help.
Otherwise, you can convert your string in an array of strings by "splitting" when the , appears, like so :
Your initial string is saved as myString
You should first remove then ( & ) at the start and the end of your string, and then do this :
NSArray* foo = [myString componentsSeparatedByString:#","];
And foo now contains these values :
"one"
two
"three"
4
But I still think you should give a little more information as i said at the start of this answer, because I have a feeling this is not exactly what you're looking for.
EDIT : as I said in comments, because it's a JSON, simply get the results into a dictionary, and then do :
NSArray *array = [results objectForKey:#"blocks"];
If your JSON is in this form, convert your JSON response in a dictionary and simply get the value of keyword "blocks" in an array. For example if you have
NSDictionary *dict = {"blocks": ["one", two, "three",4]};
The following will be your array
NSArray *array = [dict valueForKey:#"blocks"];

How to process response from Instapaper API?

I make a request to the Instapaper API, and it's supposed to return JSON. It returns something close to JSON, but not completely, like follows:
2013-05-30 19:54:20.155 --[53078:c07] (
{
type = meta;
},
{
"subscription_is_active" = 1;
type = user;
"user_id" = --;
username = "--#gmail.com";
},
{
"bookmark_id" = 387838931;
description = "";
hash = YHwQuwhW;
"private_source" = "";
progress = 0;
"progress_timestamp" = 0;
starred = 0;
time = 1369954406;
title = "Adobe Finally Releases Kuler Color-Picking App for iPhone - Mac Rumors";
type = bookmark;
url = "http://www.macrumors.com/2013/05/30/adobe-finally-releases-kuler-color-picking-app-for-iphone/";
},
How do I then process this? Can I take it and turn it into an NSDictionary even though it doesn't seem to be valid JSON?
From Instapaper API Docs:
Instapaper strings are always encoded in UTF-8, and Instapaper expects all input to be in UTF-8.
Unless otherwise noted, output from every method is an array. The output array is returned as JSON by default.
You can specify a jsonp parameter with a callback function name, e.g. jsonp=myCallback, to use JSONP and wrap the output in a call to the specified function.
So there is no way you will get not valid JSON!
Try following code:
NSData *jsonData = [[NSString stringWithContentsOfURL:[NSURL urlWithString:#"http://your-instapeper-API-link"] encoding:NSUTF8StringEncoding error:nil] dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
id serializationJSON = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
And then you can log what is wrong or if result is what you expect:
NSLog(#"class of JSON input: %# \n and possible error: %#",[serializationJSON class],error);
Of course you should expect Array and no error.
EDIT ... based on coment code:
Based on docs you should get Array or Dictionary. Please add this core instead your line #23 (numer from here):
if([JSON isKindOfClass:[NSDictionary class]]) {
NSDictionary *jsonDictionary = JSON;
NSLog(#"%#",[jsonDictionary allKeys]);
} else {
NSLog(#"JSON object class: %#",[JSON class]);
}
and please show us output.
One more thing:
You get array from request. Great! This is a valid JSON. So you need to debug it. As i said it's a shame is not a unlimited acccess public API, so i can look into it. But now you have to debug your result. I see in your code that you are trying to access bookmarks. So i look into Bookmarks section in docs and this is some kind of list (NSArray). So if you don't know what result you want. You should print them into log (or set a breakpoint). Replace code from my earlier update with this simple log:
NSDictionary *resultDictionary;
if([JSON isKindOfClass:[NSArray class]]) {
NSArray *jsonArray = JSON;
NSLog(#"so json is an array with %i objects",[jsonArray count]);
for(id objectInsideArr in jsonArray) {
NSLog(#"object in array [class]: %# [value]: %#",[objectInsideArr class],objectInsideArr); //if here you find NSDictionary maybe is this dictionary you are looking for. I'm not sure what it is.
if([objectInsideArr isKindOfClass:[NSDictionary class]]) {
resultDictionary = [[NSDictionary alloc] initWithDictionary:objectInsideArr];
}
}
}
If it were me I would write a custom formatter to get it into JSON format and then use NSJSONSerialization once I know it is valid. What you posted is so far from valid there is no way it would work. I'm surprised they are returning it in that format, do they provide some kind of library for consuming their services?
If you want something even simpler, I can give you my CGIJSONObject library that will handle JSON using reflection - you just need to mirror the keys in APIs with your classes andit is good to go.

Resources