I want to change the Dictionary's all value to String, how to do with it?
Such as:
{ #"a":"a",
#"b":2,
#"c":{
#"c1":3,
#"c2":4
}
}
I want convert to :
{ #"a":"a",
#"b":"2",
#"c":{
#"c1":"3",
#"c2":"4"
}
}
How to do with it? I think all the day.
If I use below method to traverse the dictionary values:
NSArray *valueList = [dictionary allValues];
for (NSString * value in valueList) {
// change the value to String
}
If the value is a dictionary, how about it?
So, someone can help with that?
You could do this with a recursive method, it changes all NSNumber values to NSString and calls itself for nested dictionaries. Since a dictionary cannot be mutated while being enumerated a new dictionary is created and populated:
- (void)changeValuesOf:(NSDictionary *)dictionary result:(NSMutableDictionary *)result
{
for (NSString *key in dictionary) {
id value = dictionary[key];
if ([value isKindOfClass: [NSDictionary class]]) {
NSMutableDictionary * subDict = [NSMutableDictionary dictionary];
result[key] = subDict;
[self changeValuesOf:value result:subDict];
} else if ([value isKindOfClass: [NSNumber class]]) {
result[key] = [NSString stringWithFormat:#"%#", value];
} else {
result[key] = value;
}
}
}
NSDictionary *dictionary = #{#"a": #"a", # "b":#2, #"c": #{#"c1": #3, #"c2":#4 }};
NSMutableDictionary *result = [NSMutableDictionary dictionary];
[self changeValuesOf:dictionary result:result];
NSLog(#"%#", result);
You can create category for a dictionary and add method some like stringValueForKey:.
The realisation can be something like this:
- (NSString)stringValueForKey:(NSString*)key
{
id value = self[key];
if( [value respondsToSelector:#selector(stringValue)])
return [value performSelector:#selector(stringValue)]
return nil;
}
Related
I have 100 key and value in nsmutabledictornary and i want to check that any value have null or not. Do you have any short function or technique?
I don't want to multiple line code like check every key and value. Your answer would be appreciated.
This code will give you the set of keys which have (non)null values. You can't store actual nil values in a dictionary, so [NSNull null] is assumed. The predicate is trivially alterable to any other condition.
NSDictionary *d = #{ #"a" : #"1", #"b" : [NSNull null] };
NSSet *nullKeys = [d keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return [d[key] isKindOfClass:[NSNull class]];
}];
NSSet *nonnullKeys = [d keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) {
return [d[key] isKindOfClass:[NSNull class]] == NO;
}];
From here, you can use the keys to generate a corresponding dictionary, if needed.
NSMutableDictionary *nonNullDict = [NSMutableDictionary dictionary];
[d enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
if ([nonnullKeys contains:key]) {
nonNullDict[key] = obj;
}
}];
If you don't need a separate list of keys, and just need the filtered dictionary, skip the first step and modify the second part to read as follows:
NSMutableDictionary *nonNullDict = [NSMutableDictionary dictionary];
[d enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSNull null]] == NO) {
nonNullDict[key] = obj;
}
}];
Write category on NSDictionary it will provide you null free dictionary. Here is the category I have written for myself.
code for .h file (interface)
#import <Foundation/Foundation.h>
#interface NSDictionary (CheckNull)
{
}
- (NSDictionary *)nullFreeDictionary;
#end
Code for .m file. (implementation)
#import "NSDictionary+CheckNull.h"
#implementation NSDictionary (CheckNull)
- (NSDictionary *) nullFreeDictionary
{
NSMutableDictionary *tempDictionary = [self mutableCopy];
for (NSString *key in tempDictionary.allKeys) {
NSString *value = [tempDictionary valueForKey:key];
if ([value isKindOfClass:[NSString class]]) {
if (value == (id)[NSNull null] || value == nil || value.length == 0) {
[tempDictionary setValue:#"" forKey:key];
}
}
}
return tempDictionary;
}
Call null free method on your dictionary using above category.
NSDictionary *dict = [dict nullFreeDictionary];
//To remove NULL from Dictionary
-(NSMutableDictionary *)removeNullFromDictionary : (NSMutableDictionary *)dict
{
// if (![dict isKindOfClass:[NSMutableDictionary class]])
// {
// }
dict = [[NSMutableDictionary alloc] initWithDictionary:dict];
for (NSString * key in [dict allKeys])
{
if ([dict[key] isKindOfClass:[NSNull class]])
{
[dict setValue:#"" forKey:key];
}
else if ([dict[key] isKindOfClass:[NSMutableDictionary class]]||[dict[key] isKindOfClass:[NSDictionary class]])
{
dict[key] = [self removeNullFromDictionary:[NSMutableDictionary dictionaryWithDictionary:dict[key]]];
}
else if ([dict[key] isKindOfClass:[NSMutableArray class]]||[dict[key] isKindOfClass:[NSArray class]])
{
dict[key] = [self removeNullFromArray:[NSMutableArray arrayWithArray:dict[key]]];
}
}
return dict;
}
//To remove NULL from Array
-(NSMutableArray *)removeNullFromArray : (NSMutableArray *)arr
{
// if (![arr respondsToSelector:#selector(addObject:)])
// {
// arr = [[NSMutableArray alloc] initWithArray:arr];
// }
arr = [[NSMutableArray alloc] initWithArray:arr];
for (int cnt = 0; cnt<[arr count]; cnt++)
{
if ([arr[cnt] isKindOfClass:[NSNull class]])
{
arr[cnt] = #"";
}
else if ([arr[cnt] isKindOfClass:[NSMutableDictionary class]]||[arr[cnt] isKindOfClass:[NSDictionary class]])
{
arr[cnt] = [self removeNullFromDictionary:[NSMutableDictionary dictionaryWithDictionary:arr[cnt]]];
}
else if ([arr[cnt] isKindOfClass:[NSMutableArray class]]||[arr[cnt] isKindOfClass:[NSArray class]])
{
arr[cnt] = [self removeNullFromArray:[NSMutableArray arrayWithArray:arr[cnt]]];
}
}
return arr;
}
I have a Array of custom objects with object having following properties optionID,OptionText. I want to get comma separated string for the optionID property. What would be the best approach to do this in iOS SDK.
for example NSString CommaSeperted = #"1,3,5" etc.
Category to NSArray:
#implementation NSArray(CustomAdditions)
- (NSString *)commaSeparatedStringWithSelector:(SEL)aSelector
{
NSMutableArray *objects = [NSMutableArray array];
for (id obj in self)
{
if ([obj respondsToSelector:aSelector]) {
IMP method = [obj methodForSelector:aSelector];
id (*func)(id, SEL) = (void *)method;
id customObj = func(obj, aSelector);
if (customObj && [customObj isKindOfClass:[NSString class]]) {
[objects addObject:customObj];
}
}
}
return [objects componentsJoinedByString:#","];
}
#end
Example:
#implementation NSDictionary(Test)
- (NSString*)optionID
{
return [self objectForKey:#"optionID"];
}
- (NSString*)OptionText
{
return [self objectForKey:#"OptionText"];
}
#end
NSArray *customObjects = #[#{#"optionID": #"id1", #"OptionText": #"text1" }, #{#"optionID" : #"id2", #"OptionText": #"text2"}];//List of Your custom objects
NSString *commaSeparatedOptionIDs = [customObjects commaSeparatedStringWithSelector:NSSelectorFromString(#"optionID")];
NSString *commaSeparatedOptionTexts = [customObjects commaSeparatedStringWithSelector:NSSelectorFromString(#"OptionText")];
Try this
NSString *commaSeparatedStringOfID = #"";
for (CustomClass *object in yourArray){
commaSeparatedStringOfID = [commaSeparatedStringOfID stringByAppendingString:[NSString stringWithFormat:#"%#,"]];
}
// removing last comma
commaSeparatedStringOfID = [commaSeparatedStringOfID substringToIndex:[commaSeparatedStringOfID length]-1];
commaSeparatedStringOfID will be your required string.
I have managed to extract the following array (which I am dumping to console) from some json. How can I get and print out the value for one of the elements, i.e. task?
Objective-C:
NSArray *array = [dict objectForKey:#"row"];
NSLog(#"array is: %#",array);
Console output:
array is: {
0 = 1;
1 = "send email";
2 = "with attachment";
ltask = "with attachment";
task = "send email";
userid = 1;
}
array looks like it is actually an NSDictionary, so reference the key to get the value for it.
NSLog(#"Task: %#", array[#"task"]);
the variable array doesn't seem to be NSArray . Does this work for you?
id array = [dict objectForKey:#"row"];
if([array isKindOfClass:[NSDictionary class]]){
NSLog(#"Value of task %#",array[#"task"]);
}
From the log, it looks like the output is an NSDictionary object, so to get the value of task key just do this
NSDictionary *myDict = dict[#"row"];
NSString *task = myDict[#"task"];
NSLog(#"task = %#", task);
if you want to confirm just check the class type using isKindOfClass: method
if([dict[#"row"] isKindOfClass:[NSDictionary class]]) {
NSDictionary *myDict = dict[#"row"];
NSString *task = myDict[#"task"];
NSLog(#"task = %#", task);
} else if([dict[#"row"] isKindOfClass:[NSArray class]]) {
NSArray *myArray = dict[#"row"];
NSDictionary *myDict = myArray[0];
NSString *task = myDict[#"task"];
NSLog(#"task = %#", task);
}
try
if ([[dictionary allKeys] containsObject:#"row"]) {
NSObject *objRow = dictionary[#"row"];
if(objRow){
if([objRow isKindOfClass:[NSArray class]]){
NSArray *arr = (NSArray *)objRow;
....
}
if([objRow isKindOfClass:[NSDictionary class]]){
NSDictionary *dic = (NSDictionary *)objRow;
....
}
}
}
I have a problem to communicate with a server. The webserver expects all parameters in the JSON object to be a string. So every number and every boolean in every container needs to be a string.
For my example I have a NSDictionary full of key values (values are all kinds of types - numbers, arrays etc.). For example:
{
"AnExampleNumber":7e062fa,
"AnExampleBoolean":0,
"AnExampleArrayOfNumber":[17,4,8]
}
Has to become:
{
"AnExampleNumber":"7e062fa",
"AnExampleBoolean":"0",
"AnExampleArrayOfNumber":["17","4","8"]
}
I tried the standard NSJSONSerializer but it doesn't give me any option to do what I need. I then tried to transform everything in the dictionary manually to be a string but that seems to be overhead. Does anyone have hint for me? Maybe a serializer that does just that or a function to convert any objects in a container to strings?
This is one way you could do it. It's non-optimized and has no error handling. It only supports the kinds of objects that NSJSONSerializer supports.
#import <Foundation/Foundation.h>
#interface NSObject(SPWKStringify)
- (id)spwk_stringify;
#end
#implementation NSObject(SPWKStringify)
- (id)spwk_stringify
{
if ([self isKindOfClass:[NSDictionary class]]) {
NSDictionary *dict = (NSDictionary *)self;
NSMutableDictionary *newDict = [[NSMutableDictionary alloc] init];
for (NSString *key in [dict allKeys]) {
newDict[key] = [dict[key] spwk_stringify];
}
return newDict;
} else if ([self isKindOfClass:[NSArray class]]) {
NSMutableArray *newArray = [[NSMutableArray alloc] init];
for (id value in ((NSArray *)self)) {
[newArray addObject:[value spwk_stringify]];
}
return newArray;
} else if (self == [NSNull null]) {
return #"null"; // representing null as a string doesn't make much sense
} else if ([self isKindOfClass:[NSString class]]) {
return self;
} else if ([self isKindOfClass:[NSNumber class]]) {
return [((NSNumber *)self) stringValue];
}
return nil;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
NSDictionary *dict = #{
#"AnExampleNumber": #1234567,
#"AnExampleBoolean": #NO,
#"AnExampleNull": [NSNull null],
#"AnExampleArrayOfNumber": #[#17, #4, #8],
#"AnExampleDictionary": #{#"innerKey": #[#55, #{#"anotherDict": #[#"foo", #[#1, #2, #"three"]]}]}
};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[dict spwk_stringify] options:NSJSONWritingPrettyPrinted error:NULL];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"result: %#", jsonString);
}
}
The output will be:
result: {
"AnExampleNumber" : "1234567",
"AnExampleNull" : "null",
"AnExampleDictionary" : {
"innerKey" : [
"55",
{
"anotherDict" : [
"foo",
[
"1",
"2",
"three"
]
]
}
]
},
"AnExampleBoolean" : "0",
"AnExampleArrayOfNumber" : [
"17",
"4",
"8"
]
}
Note: Please keep in mind that turning [NSNull null] into a string doesn't make any sense and might actually be misleading and dangerous.
Enjoy.
(I assume you mean NSJSONSerializer, not NSSerializer.)
I doubt you'll find a pre-rolled solution to this. It's not a general problem. As you note, this is incorrect JSON, so JSON serializers shouldn't do it.
The best solution IMO is just write the code to transform your NSDictionary into another NSDictionary that is in the form you want. If you really want to make it a generic solution, I suspect that a custom NSDictionary walker with isKindOfClass: is your best bet. Something like this should work:
NSDictionary *myStringDictForDict(NSDictionary *dict); // forward decl if needed
NSArray *myStringArrayForArray(NSArray *array) {
NSMutableArray *result = [NSMutableArray new];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[NSArray class]]) {
[result addObject:myStringArrayForArray(obj)];
} else if ([obj isKindOfClass:[NSDictionary class]]) {
[result addObject:myStringDictForDict(obj)];
} else {
[result addObject:[obj description]];
}
}];
return result;
}
NSDictionary *myStringDictForDict(NSDictionary *dict) {
NSMutableDictionary *result = [NSMutableDictionary new];
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSArray class]]) {
result[key] = myStringArrayForArray(obj);
} else if ([obj isKindOfClass:[NSDictionary class]]) {
result[key] = myStringDictForDict(obj);
} else {
result[key] = [obj description];
}
}];
return result;
}
Nesting means taking an array of key value pairs and grouping them hierarchically by a specified key. See this page for examples: http://bl.ocks.org/d/3176159/. If not, I'll just try to port https://github.com/mbostock/d3/blob/master/src/core/nest.js over but I don't want to reinvent the wheel.
This is the answer that I came up with. Let me know if you have suggestions for improvements.
// Wrapper method
// keys are in order of hierarchy
- (NSMutableArray *)nestArray:(NSArray *)array withKeys:(NSArray *)keys
{
return [self nestArray:array withKeys:keys depth:0];
}
// Private
// Assumes arrays of dictionaries with strings as the entries.
- (NSMutableArray *)nestArray:(NSArray *)array withKeys:(NSArray *)keys depth:(int)depth
{
// Current key
NSString *key = [keys objectAtIndex:depth];
depth++;
// Create dictionary of the keys
NSMutableDictionary *map = [[NSMutableDictionary alloc] init];
for (NSDictionary *dictionary in array) {
NSString *value = [dictionary objectForKey:key];
if ([map objectForKey:value]) {
[[map objectForKey:value] addObject:dictionary];
} else {
[map setObject:[NSMutableArray arrayWithObject:dictionary] forKey:value];
}
}
NSMutableArray *nest = [[NSMutableArray alloc] init];
for (NSString *valkey in [map allKeys]) {
NSMutableArray *values = [map objectForKey:valkey];
if (depth < keys.count) {
values = [self nestArray:[NSArray arrayWithArray:array] withKeys:keys depth:depth];
}
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:valkey,#"key",values,#"values", nil];
[nest addObject:dictionary];
}
return nest;
}