Objective-C String handling issue - objective-c

I'm trying to read from a JSON response something like below
{
"URL":
{
"target": "www.google.com",
"0": [ 92, 15 ],
"1": [ 92, 16 ],
"2": [ 74, 15 ],
"4": [ 5, 16 ]
}
}
Using SBJSON I've managed to get 'target' field,
testString = [[result objectForKey:#"URL"] objectForKey:#"target"];
when I do a NSLOG it shows www.google.com
but this piece of code doesn't work for other key pairs.
testString = [[result objectForKey:#"URL"] objectForKey:#"0"];
and when I try to print testString it gives me an error.
In console I printed values, they were,
(lldb) po testString
(NSString *) $4 = 0x0864b190 <__NSArrayM 0x864b190>(
65,
27
)
How do I extract these 65 and 27 ?

that is an array of objects. try:
NSArray * array = [[result objectForKey:#"URL"] objectForKey:#"0"];
id a = [array objectAtIndex:0]; // 65
id b = [array objectAtIndex:1]; // 27
// now determine the type of objects in the array, and use them appropriately:
if ([a isKindOfClass:[NSString class]]) {
NSString * string = a;
...use appropriately
}
else if ([a isKindOfClass:[NSDecimalNumber class]]) {
NSDecimalNumber * number = a;
...use appropriately
}
...
else {
assert(0 && "type not supported");
}

Do this:
if([result objectForKey:#"URL"] objectForKey:#"0"] isKindofClass:[NSArray class])
{
NSArray *arritems = [[result objectForKey:#"URL"] objectForKey:#"0"];
NSMutableArray *values = [NSMutableArray array];
for( id *item in arritems)
{
if([item is isKindOfClass:[NSString class]])
{
NSString * valueStr = item;
[values addObject:valueStr];
}
else if([item is isKindOfClass:[NSDecimalNumber class]])
{
NSDecimalNumber * valueNum = item;
[values addObject:valueNum];
}
}
NSLog(#"%#",values);
}
Same logic repeat for keys value 1 , 2 , 3

NSArray *data = [[result objectForKey:#"URL"] objectForKey:#"0"];
Then your items are in [data objectAtIndex:0] and [data objectAtIndex:1]

Related

find item and then remove it in NSMutableData array

I have NSMutableData array of bytes. I need to find item and then delete it.
my code:
NSArray *array = [[tunerButtonHostInfo objectForKey:#"local"] objectForKey:#"snPacket"];
NSMutableData *asciiData = [[NSMutableData alloc] init];
[asciiData appendData [#"\x00\x00\x02\x00\x00\x0e"dataUsingEncoding:NSASCIIStringEncoding]];
if(array != nil && ![array isKindOfClass:[NSNull class]] && [array isKindOfClass:[NSArray class]]) {
for(NSNumber *asciiCode in array) {
int asc = [asciiCode intValue];
if(asc == 0) {
NSString *string = #"\x00"; dataUsingEncoding:NSASCIIStringEncoding]];
}
else {
NSString *converted = [NSString stringWithFormat:#"%c", asc];
[asciiData appendData:[converted dataUsingEncoding:NSUTF8StringEncoding]];
}
}
NSLog(#"stringAsciiData"); //print asciiData
NSLog(#"%#", asciiData);
output of asciiData is:
00000200 000e6808 08680064 6c0b0367 6308c2b0 16
I need to find "c2" in the array and then remove it and shift remaining data in array to the left
Here is the modification to code to c2 . You can use append bytes method instead of converting to string and printing it back:
{
NSArray *array = #[#68,#0x08,#0x08,#68,#00,#64,#0x6c,#0x0b,#03,#67,#63,#0x08,#0xc2,#0xb0,#16];
NSMutableData *asciiData = [[NSMutableData alloc] init];
[asciiData appendData:[#"\x00\x00\x02\x00\x00\x0e"dataUsingEncoding:NSASCIIStringEncoding]];
if(array != nil && ![array isKindOfClass:[NSNull class]] && [array isKindOfClass:[NSArray class]]) {
for(NSNumber *asciiCode in array) {
Byte asc = [asciiCode intValue];
if(asc == 0) {
NSString *string = #"\x00";
[asciiData appendData:[string dataUsingEncoding:NSASCIIStringEncoding]];
}else if(asc != 0xc2) {
[asciiData appendBytes:&asc length:1];
}
}
NSLog(#"stringAsciiData"); //print asciiData
NSLog(#"%#", asciiData);
}
}

Change json format in NSDictionary (Objective C)

I am new in ios programming. I should apply data to the chart. But the framework(ShinobiControls) which I use accepts only json with certain format. So I have to change my json data format to appropriate. I have NSDictionary which contain json like this:
"data": [
"01.01.2015",
"01.01.2015",
"01.01.2015",
"01.01.2015"]
"close": [
[
1,
1,
1,
1]
And now I should change format of the json like this:
[
{
"date": "01.01.2015",
"close": 1
},
{
"date": "01.01.2015",
"close": 1
},
{
"date": "01.01.2015",
"close": 1
},
{
"date": "01.01.2015",
"close": 1
}
]
I did some manipulation with converting NSDictionary to NSArray, but didn't get anything. How can I do it? Do you have any ideas? Thank you.
So if i understand your question right, you have a dictionary that contains 2 arrays and you want to convert it to an array that contains dictionaries , assuming that that the count of the arrays in the dictionary is equal, you can do the following
//This is the first array in your dictionary
NSArray * dataArr = [data objectForKey:#"data"] ;
//This the second array in your dictionary
NSArray * closeArr = [data objectForKey:#"close"] ;
NSUInteger dataCount = [dataArr count] ;
NSUInteger closeCount = [closeArr count] ;
//This will be your result array
NSMutableArray * newData = [NSMutableArray new] ;
//The loop condition checks that the current index is less than both the arrays
for(int i = 0 ; i<dataCount && i<closeCount ; i++)
{
NSMutableDictionary * temp = [NSMutableDictionary new] ;
NSString * dataString = [dataArr objectAtIndex:i];
NSString * closeString = [closeArr objectAtIndex:i];
[temp setObject:dataString forKey:#"date"];
[temp setObject:closeString forKey:#"close"] ;
[newData addObject:temp];
}
NSArray *Arr = [[NSArray alloc] initWithObjects:#"01.01.2015",#"01.01.2015",#"01.01.2015",#"02.01.2015", nil];
NSArray *Arr1 = [[NSArray alloc] initWithObjects:#"1",#"1",#"1",#"1", nil];
NSDictionary *Dic = [[NSDictionary alloc] initWithObjectsAndKeys:Arr,#"data",Arr1,#"close", nil];
NSLog(#"%#",Dic);
NSMutableArray *ArrM = [[NSMutableArray alloc] init];
for ( int i = 0; i<Arr.count; i++) {
NSDictionary *Dic = [[NSDictionary alloc] initWithObjectsAndKeys:Arr[i],#"data",Arr1[i],#"close", nil];
[ArrM addObject:Dic];
}
NSLog(#"%#",ArrM);
NSError * err;
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:ArrM options:0 error:&err];
NSString * myString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"%#",myString);

How to parse JSON

How to parse this below "choices" on one array means when I have get "id" in array that all id values 108,109.... in 1st index in array but here is the 5 values in choices..so how to parse it
choices = (
{
id = 108;
label = Distributor;
},
{
id = 109;
label = "Clinical Lab";
},
{
id = 110;
label = Researcher;
},
{
id = 111;
label = "Current Customer";
},
{
id = 112;
label = "Past Customer";
}
);
Get in a single Step bro as
If your array is NSMutableArray then use as
NSArray *resultArray = [[NSArray arrayWithArray:temp] valueForKeyPath:#"id"]
If simple NSArray then use as
NSArray *resultArray = [jsonArray valueForKeyPath:#"id"]
You can do it using fast enumeration.
NSMutableArray *resultArray = [[NSMutableArray alloc] initWithCapacity:0];
// JSONDict is your JSON dict
for (NSDictionary *aDict in JSONDict[#"choices"]) {
[resultArray addObject:aDict[#"id"]];
}
NSLog(#"%#", resultArray);
Output:
(
108,
109,
110,
111,
112
)
If i understand your question properly, Then You can try this code for getting Ids in a Array:
NSMutableArray *arr = [[NSMutableArray alloc] init];
for (int i = 0;i<[choices count];i++)
{
[arr addObject:[[choices objectAtIndex:i] objectForKey:#"id"]];
}
NSLog(#"ID array : %#",arr);
[arr release];
try like this ,
NSMutableArray *idArray=[[NSMutableArray alloc]init];
for(int i=0;i<[jsonArray count];i++)
[idArray addObject:[[jsonArray objectAtIndex:i] valueForKey:#"id"]];
NSLog(#"%#",idArray);
here you'l get all the values in idArray.

NSUSerDefaults with NSMutableArray sort by desc order

I'm breaking my head on why descending order sort is not working with the following code. I wanted to limit by top 5 scores and other logic. The scores would look like this: 22/30, 12/18, 34/38, 23/32 etc. I added/removed SortDescriptor to sort by descending order and it seems to work for the first 3 items but then is not sorting properly. Can somebody help?
- (NSMutableArray*) method1:(NSString *) mode byScore: (NSString *) score
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *array = [[defaults objectForKey:mode]mutableCopy];
if (!array)
{
array = [[NSMutableArray alloc] init];
}
NSLog(#"The content of array is%#", array);
if ([array count] < 5)
{
if (![array containsObject:score])
{
[array addObject:score];
// Need to sort here. But not too sure this is the right place
NSLog(#"The content of the sorted array upto 5 is%#", array);
}
}
else
{
if (![array containsObject:score])
{
if ([array lastObject] < score)
{
[array addObject:score];
// Need to sort here before I remove the last object
[array removeLastObject];
NSLog(#"The content of the sorted array else is%#",array);
}
}
}
[defaults setObject:array forKey:mode];
[defaults synchronize];
// I want the array in NSUserDefaults to be sorted in desc order
// don't know what to return here ==> the array object or the defaults object cast to NSMutableArray?
}
Helper function
static NSComparisonResult CompareFloats( float a, float b )
{
if ( a < b ) { return NSOrderedAscending ; }
else if ( a > b ) { return NSOrderedDescending ; }
return NSOrderedSame ;
}
Category on NSString
#implementation NSString (Stuff)
-(float)floatValueForFraction
{
NSArray * components = [ self componentsSeparatedByString:#"/" ] ;
return [ components[0] floatValue ] / [ components[1] floatValue ] ;
}
#end
Your method:
- (void)addScore:(NSString*)score forMode:(NSString*)mode
{
NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
NSArray * scores = [ defaults objectForKey:mode ] ;
scores = scores ? [ scores arrayByAddingObject:score ] : #[ score ] ;
scores = [ scores sortedArrayUsingComparator:^(NSString * a, NSString * b){
return CompareFloats( [ a floatValueForFraction ], [ b floatValueForFraction ] ) ;
}]
if ( scores.count > 5 ) { scores = [ scores subarrayWithRange:(NSRange){ .length = 5 } ] ; }
[ default setObject:scores forKey:mode ] ;
}
If you want the updated high scores after calling this method, just use [ [ NSUserDefaults standardUserDefaults ] objectForKey:<mode> ]. It's better to have your methods just do one thing.
One approach to sorting array:
First define a block getNumeratorAndDenominatorFromScoreString as follows:
BOOL (^getNumeratorAndDenominatorFromScoreString)(NSString *, NSInteger *, NSInteger *) = ^(NSString *scoreString, NSInteger *numeratorOut, NSInteger *denominatorOut) {
BOOL res = NO;
NSArray *components = [scoreString componentsSeparatedByString:#"/"];
if (components &&
[components count] == 2) {
res = YES;
if (numeratorOut) {
NSNumber *numeratorNumber = [components objectAtIndex:0];
*numeratorOut = [numeratorNumber integerValue];
}
if (denominatorOut) {
NSNumber *denominatorNumber = [components objectAtIndex:1];
*denominatorOut = [denominatorNumber integerValue];
}
}
return res;
};
Then use this block together with -[NSArray sortedArrayUsingComparator] to sort array:
NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj1, id obj2) {
NSComparisonResult res = NSOrderedSame;
NSString *score1 = (NSString *)obj1;
NSString *score2 = (NSString *)obj2;
NSInteger numerator1, denominator1, numerator2, denominator2;
BOOL res1, res2;
res1 = getNumeratorAndDenominatorFromScoreString(score1, &numerator1, &denominator1);
res2 = getNumeratorAndDenominatorFromScoreString(score2, &numerator2, &denominator2);
if (res1
&& res2) {
CGFloat value1 = ((CGFloat)numerator1)/((CGFloat)denominator1);
CGFloat value2 = ((CGFloat)numerator2)/((CGFloat)denominator2);
if (value1 > value2) {
res = NSOrderedDescending;
} else if (value1 < value2) {
res = NSOrderedAscending;
}
}
return res;
}];
This will order array from least to greatest. To order from greatest to least, just replace
if (value1 > value2) {
res = NSOrderedDescending;
} else if (value1 < value2) {
res = NSOrderedAscending;
}
with
if (value1 > value2) {
res = NSOrderedAscending;
} else if (value1 < value2) {
res = NSOrderedDescending;
}
A readable structure for this method would be, in [mostly not] pseudocode
- (void)addScoreToHighscores:(NSString *)score withMethod:(NSString *)mode
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *currentHighscores = [defaults arrayForKey:mode];
if (!currentHighscores) currentHighscores = [NSArray array];
if (![currentHighscores containsObject:score]) {
currentHighscores = [currentHighscores arrayByAddingObject:score];
//sort currentHighscores: adapt the above code so that we have
BOOL (^getNumeratorAndDenominatorFromScoreString)(NSString *, NSInteger *, NSInteger *) = //as above
NSArray *newHighscores = [currentHighscores sortedArrayUsingComparator:^(id obj1, id obj2) {
//as above
}];
//truncate newHighscores
if ([newHighscores count] > 5) {
newHighscores = [newHighscores subarrayWithRange:NSMakeRange(0,5)];
}
[defaults setObject:newHighscores forKey:mode];
} else {
//since score is already in currentHighscores, we're done.
return;
}
}
If you need to screen out scores the strings for which are not equal but the evaluations of the fractions for which are equal (#"1/2" and #"5/10"), you'll need to be more clever.
Here is the full code sketched out above:
- (void)addScoreToHighscores:(NSString *)score withMethod:(NSString *)mode
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *currentHighscores = [defaults arrayForKey:mode];
if (!currentHighscores) currentHighscores = [NSArray array];
if (![currentHighscores containsObject:score]) {
currentHighscores = [currentHighscores arrayByAddingObject:score];
//sort currentHighscores: adapt the above code so that we have
BOOL (^getNumeratorAndDenominatorFromScoreString)(NSString *, NSInteger *, NSInteger *) = ^(NSString *scoreString, NSInteger *numeratorOut, NSInteger *denominatorOut) {
BOOL res = NO;
NSArray *components = [scoreString componentsSeparatedByString:#"/"];
if (components &&
[components count] == 2) {
res = YES;
if (numeratorOut) {
NSNumber *numeratorNumber = [components objectAtIndex:0];
*numeratorOut = [numeratorNumber integerValue];
}
if (denominatorOut) {
NSNumber *denominatorNumber = [components objectAtIndex:1];
*denominatorOut = [denominatorNumber integerValue];
}
}
return res;
};
NSArray *newHighscores = [currentHighscores sortedArrayUsingComparator:^(id obj1, id obj2) {
NSComparisonResult res = NSOrderedSame;
NSString *score1 = (NSString *)obj1;
NSString *score2 = (NSString *)obj2;
NSInteger numerator1, denominator1, numerator2, denominator2;
BOOL res1, res2;
res1 = getNumeratorAndDenominatorFromScoreString(score1, &numerator1, &denominator1);
res2 = getNumeratorAndDenominatorFromScoreString(score2, &numerator2, &denominator2);
if (res1
&& res2) {
CGFloat value1 = ((CGFloat)numerator1)/((CGFloat)denominator1);
CGFloat value2 = ((CGFloat)numerator2)/((CGFloat)denominator2);
if (value1 > value2) {
res = NSOrderedDescending;
} else if (value1 < value2) {
res = NSOrderedAscending;
}
}
return res;
}];
//truncate newHighscores
if ([newHighscores count] > 5) {
newHighscores = [newHighscores subarrayWithRange:NSMakeRange(0,5)];
}
[defaults setObject:newHighscores forKey:mode];
} else {
//since score is already in currentHighscores, we're done.
return;
}
}

Parse nested JSON Object in Objective-C

Perhaps I am over-thinking or confusing myself, but my head is stuck in a loop over this and I cannot break out.
I have a a JSON of the format: (Validated at http://jsonformatter.curiousconcept.com/)
{
id: 1,
sections: "5",
total: "10",
result: {
3: 00PM: [
{
name: "Anurag",
status: "Web"
},
{
name: "Anurag2",
status: "Web2"
}
],
5: 00PM: [
{
name: "Anurag",
status: "Seated"
}
],
6: 00PM: [
{
name: "Anurag4",
status: "Web4"
},
{
name: "Anurag5",
status: "Web5"
},
{
name: "Anurag6",
status: "Web6"
},
{
name: "Anurag7",
status: "Web7"
}
]
}
}
I have this so far:
NSDictionary *dict = [response JSONValue];
NSDictionary *results = [dict objectForKey:#"result"];
NSInteger num_results = [[dict valueForKey:#"total"] intValue];
NSInteger num_sections = [[dict valueForKey:#"sections"] intValue];
NSMutableArray *sections = [[NSMutableArray alloc] initWithCapacity:num_sections];
NSMutableArray *objarr = [[NSMutableArray alloc] initWithCapacity:num_results];
NSMutableArray *obj= [[NSMutableArray alloc] initWithCapacity:num_sections];
NSMutableArray *temp = [[NSMutableArray alloc] initWithCapacity:num_results];
for (NSString* key in results) {
NSLog(#"Key: %#", key); // prints out 3:00 PM...5:00 PM etc...
[obj addObject:[results objectForKey:key]]; // nested objects within each key are saved in the array
NSLog(#"Object 1: %#", obj);
}
for (int i = 0; i < [obj count]; i++) {
//NSLog(#"Object 2: %#", [obj objectAtIndex:i]);
[temp addObject:[obj objectAtIndex:i]]; // I take each object from previous array and save it in a temp array
for (int i = 0; i < num_results; i++) {
NSLog(#"Object 3: %#", [temp objectAtIndex:i]);
**[objarr addObject:[temp objectAtIndex:i]]; // I want to extract the object within the object but cannot get it to work**
}
}
I am able to make an array of objects within each of the 3 keys inside results. But I am not able to get each of the objects inside them as a separate object and save them in an array.
For example, in an NSArray I have:
Object 3: (
{
name = "Anurag ";
status = Web;
},
{
name = "Anurag ";
status = Web;
}
)
How can I get the two objects inside this object and save them both in an array?
I guess the main issue is I cannot refer to a key name to get the individual object.
You can use the following code,
NSDictionary *json = [response JSONValue];
// Get the objects you want
NSArray *items = [json valueForKeyPath:#"result.6: 00PM"];
This will return an NSArray with the objects for the key 6: 00PM
Please check this link too.
You are redefining int i in your second for loop. Try something like
for(int j = 0; j < num_results; j++)
[temp addObject:[obj objectAtIndex:i]]; // I take each object from previous array and save it in a temp array
This is useless motion. You're effectively just copying the obj array to the temp array -- no value added.