objc Separating tuples - objective-c

ran into a simple objc problem and need some help. I'm sending a query to a server that gives me back a tuple wrapped in jSON. Just using the dictionary to sort everything out.
- (void)viewDidLoad
{
[super viewDidLoad];
Nodes *node = [Nodes new];
NSDictionary *jsonDict = [node nodeActivityforNode:#"17" withDates:nil and:nil];
NSDictionary *jsonActivityDict = [jsonDict objectForKey:#"activity"];
NSLog(#"activity?: %#", jsonActivityDict);
}
and then heres the debug dump
activity?:
(
(
"2013-05-21 16:58:32",
0
),
(
"2013-05-21 16:58:15",
0
),
(
"2013-05-21 16:57:59",
0
),
I'm trying to split up the comma separated values so I can put them in individual int and string objects but just cant think of how to get in there. Any help would be appreciated. Thanks!

The "activity" data looks like an array of arrays, not a dictionary. If you know you will always get three pairs of values and you want those 6 values put into 6 separate variables then you could do this:
NSDictionary *jsonDict = [node nodeActivityforNode:#"17" withDates:nil and:nil];
NSArray *jsonActivities = [jsonDict objectForKey:#"activity"];
NSString *date1 = jsonActivities[0][0];
int int1 = [jsonActivities[0][1] intValue];
NSString *date2 = jsonActivities[1][0];
int int2 = [jsonActivities[1][1] intValue];
NSString *date3 = jsonActivities[2][0];
int int3 = [jsonActivities[2][1] intValue];
Note that this code will crash if there are less than 3 sets of pairs or if any of those three "pairs" only has one value instead of two.

Related

Bug in my code using NSArray crashes

I'm making a code which shows the names of people on a list.
The list is different for each date, so my problem is when there is only like 1 or no people signed and I make an array with index beyond the limit of people, it crashed. I know that this happens because the array is empty, but how do I make the code ignore empty arrays?
I have tried to make an "if" that count the number of arrays and then decide to post the array or just post no name. But it doesn't work like this, I still get the out of bounds exception.
How should I manage empty arrays?
My code:
NSString *html = [request2 responseString];
NSMutableArray *arr2 = [html componentsSeparatedByString:#"vagter"];
NSString *html1 = [arr2 objectAtIndex:1];
//name1
NSMutableArray *arr3 = [html1 componentsSeparatedByString:#"<td><font color=#ffffff>"];
NSString *html2 = [arr3 objectAtIndex:1];
NSMutableArray *arr4 = [html2 componentsSeparatedByString:#"</font></td>"];
NSString *html3 = [arr4 objectAtIndex:0];
_name.text = html3;
//name 2
NSMutableArray *arr5 = [html1 componentsSeparatedByString:#"<td><font color=#ffffff>"];
if ([arr5 count] > 4) {
NSString *html4 = [arr5 objectAtIndex:5];
NSMutableArray *arr6 = [html4 componentsSeparatedByString:#"</font></td>"];
NSString *html5 = [arr6 objectAtIndex:0];
_name.text = html5;
}
else
{
_name1.text = #"No name";
}
It should be:
if ([arr5 count] > 5) {
NSString *html4 = [arr5 objectAtIndex:5];
...
Indeed, index 5 will correspond to the sixth array item, so you have to have at least 6 objects in it.
Use the same pattern, if you want to check for the array bounds, in all cases.
The problem is that you expect the return from componentsSeparatedByString to return consistent results according to your expectations.
Clearly thats not working.
Array handling is simple. Dont ask for objects that arent there.
Check the count and only access indexes from 0 to count - 1;
If count is zero dont access anything.

extracting data from an array of arrays

I have the following code:
NSString *movies = [[NSString alloc] initWithData:webData7 encoding:NSUTF8StringEncoding];
NSLog(#"movies: %#", movies);
array_webdata = [parsedata objectWithString:movies error:nil];
userMovies = [array_webdata valueForKey:#"movies"];
NSLog(#"userMovies: %#", userMovies);
NSMutableArray *arrayCodes = [userMovies valueForKey:#"rtid"];
NSLog(#"arrayCodes: %#", arrayCodes);
In first line I save in movies the following:
movies:
{"movies":[["rtid","770672122"],["rtid","771268706"],["rtid","771240265"],["rtid","9377"]]}
with: userMovies = [array_webdata valueForKey:#"movies"]; I store in userMovies:
userMovies: (
rtid,
770672122
),
(
rtid,
771268706
),
(
rtid,
771240265
),
(
rtid,
9377
)
From here I want to extract the numbers to create another array like :
codes: (770672122, 771268706, 771240265, 9377)
But with following line, the execution crashes:
NSMutableArray *arrayCodes = [userMovies valueForKey:#"rtid"];
The error is EXC_BAD_ACCESS. On Debug Area shows no errors
Do you know what is wrong?
Thanks!
I have edited the question to make it more understandable
The code you have is clearly not going to work because you are assigning a number (or int, or some type) to a mutable array. You can't do that. You need to ADD them to the array since they will be contained IN THE ARRAY, those numbers ARE NOT arrays...
How are you getting it from JSON? Your array is probably an array of NSDictionary's so you'll want to do something like:
for (NSDictionary *aDictionary in userMovies)
{
[arrayCodes addObject: [aDictionary valueForKey:#"rtid"]];
}
You need to start by finding out what's in your array. Do:
NSLog(#"My array contains %#'s", [[userMovies valueForKey:#"rtid"] class]);
From there, if you get NSDictionary use the code above, and if you get an array, you'll have to loop through the array like:
for (NSArray *anArray in userMovies)
{
[arrayCodes addObject: [anArray objectAtIndex:1]];
}
SOLVED!
I have deleted my last two lines of code:
NSMutableArray *arrayCodes = [userMovies valueForKey:#"rtid"];
NSLog(#"arrayCodes: %#", arrayCodes);
and added the following
NSMutableArray *moviesCodes = [[NSMutableArray alloc] init];
for (int counter = 0; counter<[userMovies count]; counter++){
[moviesCodes addObject:[[userMovies objectAtIndex:counter] objectAtIndex:1]];
}
With this I have stored all the ids in the array called moviesCodes. The problem was that userMovies is an array of arrays

Objective C : Writing into a Plist

Even though i know there are at least 2 or 3 topics with this name, i didnt find a proper answer so far to my problem :
I want to edit a Plist (which has been created by zwoptex (image/animations program)) in order to divide every number in it by 2.
So in my plist i do have some keys like "spriteOffset" with {{182, 160}, {58,75}} or {192, 165} as value. Those are NSStrings, and i just want to modify the numbers so i need to check if there's a "{" or a space or such, then casting the number.
The thing is i don't really know how to do it.....
Also, it seems that i'm missing something with my plist management. I've put some NSLogs for displaying every of those strings in my plist, but.... nothing gets displayed...
So here is my code :
-(void)DivideValues
{
for(NSString * plistName in plistSubpathsByName)
{
NSMutableDictionary* infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:#"%#.plist",plistName]];
for(NSDictionary * sprite in [infoDict objectForKey:#"frames"])
{
for(NSString * string in [infoDict objectForKey:#"spriteColorRect"])
{
NSLog(#"%#",string);
}
for(NSString * string in [infoDict objectForKey:#"spriteOffset"])
{
NSLog(#"%#",string);
}
for(NSString * string in [infoDict objectForKey:#"spriteSize"])
{
NSLog(#"%#",string);
}
for(NSString * string in [infoDict objectForKey:#"spriteSourceSize"])
{
NSLog(#"%#",string);
}
for(NSString * string in [infoDict objectForKey:#"textureRect"])
{
NSLog(#"%#",string);
}
}
}
}
Thanks for any response, and i wish you all good luck for your career/passion
First of all, you should replace [infoDict objectForKey:#"spriteColorRect"] with [sprite objectForKey:#"spriteColorRect"], since the sprite is probably the dict containing further information.
You don't see any logs because -objectForKey: returns nil for a key that does not exist.
For changing the values, you might try to create a CGPoint or CGRect from the string, then changing it and finally converting it back to a string. (CGPointFromNSString() and NSStringFromCGPoint)
To save the modified version of your dictionary use NSDictionary's -writeToFile:atomically:.
The reason you example logs nothing is most likely because your inner for..in loops are probably looking in the wrong dictionary: the outer loop gets a dictionary sprite, so shouldn't the inner loops be looking at keys in that dictionary?
If you want to read a property list in, change some values in it, and write the same property list back out, you might find it useful to look at the NSPropertyListSerialization class -- it lets you quickly get a structure of mutable arrays/dictionaries from plist data, so you can iterate into them however you'd like to change values within, then serialize the whole thing back to data again. (If you use dictionaryWithContentsOfFile: you'll get a mutable dictionary, but all the containers within it will be immutable, so you'd have to do mutableCopy and swizzle contents all over the place during your iteration.)
No time to write up more detail at the moment, but I might edit the answer later if looking up the docs for NSPropertyListSerialization doesn't help you.
Ok I did succeed so if anyone is interested here is the code :
-(void)DivideValues
{
for(NSString * xflName in [xflSubpathsByName objectEnumerator]){
NSMutableDictionary* infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:[sourceFolder stringByAppendingPathComponent:xflName]];
NSDictionary * dictionary = [infoDict objectForKey:#"frames"];
NSMutableDictionary * mutabledictionary = [[dictionary mutableCopy] autorelease];
for(NSString * pngFileName in dictionary) {
NSDictionary * sprite = [dictionary objectForKey:pngFileName];
NSLog(pngFileName);
NSMutableDictionary * mutablesprite = [[sprite mutableCopy] autorelease];
NSString * newstring = [self castSpriteRect:[sprite objectForKey:#"spriteColorRect"]];
[mutablesprite setObject:newstring forKey:#"spriteColorRect"];
newstring = [self castSprite:[sprite objectForKey:#"spriteOffset"]];
[mutablesprite setObject:newstring forKey:#"spriteOffset"];
newstring = [self castSprite:[sprite objectForKey:#"spriteSize"]];
[mutablesprite setObject:newstring forKey:#"spriteSize"];
newstring = [self castSprite:[sprite objectForKey:#"spriteSourceSize"]];
[mutablesprite setObject:newstring forKey:#"spriteSourceSize"];
newstring = [self castSpriteRect:[sprite objectForKey:#"textureRect"]];
[mutablesprite setObject:newstring forKey:#"textureRect"];
[mutabledictionary setObject:mutablesprite forKey:pngFileName];
}
[infoDict setObject:mutabledictionary forKey:#"frames"];
[infoDict writeToFile:[sourceFolder stringByAppendingPathComponent:xflName] atomically:NO];
}
if(!cancelling)
++digestStage;
else
digestStage = End;
}
-(NSString *)castSprite:(id)obj{
CGPoint point = NSPointFromString((NSString *)obj);
int i = (int)point.x%2 == 0 ?(int)point.x/2:1+(int)point.x/2;
int j = (int)point.y%2 == 0 ?(int)point.y/2:1+(int)point.y/2;
NSString * res = [NSString stringWithFormat:#"{%d, %d}",i,j];
return res;
}
-(NSString *)castSpriteRect:(id)obj{
CGRect point = NSRectFromString((NSString *)obj);
int i = (int)point.origin.x%2 == 0 ?(int)point.origin.x/2:1+(int)point.origin.x/2;
int j = (int)point.origin.y%2 == 0 ?(int)point.origin.y/2:1+(int)point.origin.y/2;
int y = (int)point.size.width%2 == 0 ?(int)point.size.width/2:1+(int)point.size.width/2;
int x = (int)point.size.height%2 == 0 ?(int)point.size.height/2:1+(int)point.size.height/2;
NSString * res = [NSString stringWithFormat:#"{{%d, %d}, {%d, %d}}",i,j,y,x];
return res;
}

Does core data do its own type casting in the background?

I am working on a simple comparison of two lists to see which items in an "evaluation" list are contained in a larger "target" list. I am getting the data on-the-fly- by parsing two CSV files and storing everything as strings. I successfully import the data into the data store and I can get a list of entities no problem
The problem comes when I actually do a search. Essentially, I am looking for short ISBNs in the form of 1234 from the evaluation list in the target list, which are in the form of 1234-5. The predicate I am using is I am using the CONTAINS comparison in the form of [NSString stringWithFormat:#"%# CONTAINS %#", kOC_Target_PrintBookCode, evalIsbn]
The error I get is the following (grabbed by my NSLog)
NSInvalidArgumentException: Can't look for value (1494) in string (49885); value is not a string
I get the impression that even though the ISBN is being read from a NSString and the Core Data store has the data point spec'd as a String, that Core Data is still doing something in the background with the value for whatever reason it sees fit. Any ideas?
Here is the relevant process logic (though I use that term dubiously) code. Unless otherwise noted in the code, all values being manipulated and/or stored are NSString:
NSArray *evalBooks = [self getEntitiesByName:kOC_EntityName_EvalBook
usingPredicateValue:[NSString stringWithFormat:#"%# > \"\"", kOC_Eval_Bookcode]
withSubstitutionVariables:nil
inModel:[self managedObjectModel]
andContext:[self managedObjectContext]
sortByAttribute:nil];
if ( ( !evalBooks ) || ( [evalBooks count] == 0 ) ) {
// we have problem
NSLog(#"( !evalBooks ) || ( [evalBooks count] == 0 )");
return;
}
[evalBooks retain];
int firstEvalBook = 0;
int thisEvalBook = firstEvalBook;
int lastEvalBook = [evalBooks count]; NSLog(#"lastEvalBook: %i", lastEvalBook);
for (thisEvalBook = firstEvalBook; thisEvalBook < lastEvalBook; thisEvalBook++) {
NSManagedObject *evalBook = [[evalBooks objectAtIndex:thisEvalBook] retain];
NSString *rawIsbn = [[evalBook valueForKey:kOC_Eval_Bookcode] retain];
NSString *isbnRoot = [[self getIsbnRootFromIsbn:rawIsbn] retain];
// this is a custom method I created and use elsewhere without any issues.
NSArray *foundBooks = [self getEntitiesByName:kOC_EntityName_TargetBook
usingPredicateValue:[NSString stringWithFormat:#"%# CONTAINS %#", kOC_Target_PrintBookCode, isbnRoot]
withSubstitutionVariables:nil
inModel:[self managedObjectModel]
andContext:[self managedObjectContext]
sortByAttribute:kOC_Target_PrintBookCode];
if ( foundBooks != nil ) {
[foundBooks retain];
NSLog(#"foundBooks: %lu", [foundBooks count]);
} else {
}
If you're building your predicate as an NSString, I believe
[NSString stringWithFormat:#"%# CONTAINS %#", kOC_Target_PrintBookCode, isbnRoot]
should actually be
[NSString stringWithFormat:#"%# CONTAINS '%#'", kOC_Target_PrintBookCode, isbnRoot]
It seems that you're confusing the way predicateWithFormat: works with the way stringWithFormat: works.
Presumably either kOC_Target_PrintBookCode or isbnRoot is not an object that can be converted to a string. E.g. if either is an integer, the %# operator cannot convert the integer to a string value.

Sorting NSStrings of Numbers

So I have an NSDictionary where the keys are years as NSString's and the value for each key is also an NSString which is sort of a description for the year. So for example, one key is "943 B.C.", another "1886". The problem I am encountering is that I want to sort them, naturally, in ascending order.
The thing is that the data source of these years is already in order, it's just that when I go ahead and call setValue:forKey the order is lost, naturally. I imagine figuring out a way to sort these NSString's might be a pain and instead I should look for a method of preserving the order at the insertion phase. What should I do? Should I instead make this an NSMutableArray in which every object is actually an NSDictionary consisting of the key being the year and the value being the description?
I guess I just answered my own question, but to avoid having wasted this time I'll leave this up in case anyone can recommend a better way of doing this.
Thanks!
EDIT: I went ahead with my own idea of NSMutableArray with NSDictionary entries to hold the key/value pairs. This is how I am accessing the information later on, hopefully I'm doing this correctly:
// parsedData is the NSMutableArray which holdes the NSDictionary entries
for (id entry in parsedData) {
NSString *year = [[entry allKeys] objectAtIndex:0];
NSString *text = [entry objectForKey:year];
NSLog(#"Year: %#, Text: %#", year, text);
}
Maintain a NSMutableArray to store the keys in order, in addition to the NSDictionary which holds all key-value pairs.
Here is a similar question.
You could either do it as an array of dictionaries, as you suggest, or as an array of strings where the strings are the keys to your original dictionary. The latter is probably a simpler way of going about it. NSDictionary does not, as I understand it, maintain any particular ordering of its keys, so attempting to sort the values there may be unwise.
I needed to solve a similar problem to sort strings of operating system names, such as "Ubuntu 10.04 (lucid)".
In my case, the string could have any value, so I sort by tokenizing and testing to see if a token is a number. I'm also accounting for a string like "8.04.2" being considered a number, so I have a nested level of tokenizing. Luckily, the nested loop is typically only one iteration.
This is from the upcoming OpenStack iPhone app.
- (NSComparisonResult)compare:(ComputeModel *)aComputeModel {
NSComparisonResult result = NSOrderedSame;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
NSArray *tokensA = [self.name componentsSeparatedByString:#" "];
NSArray *tokensB = [aComputeModel.name componentsSeparatedByString:#" "];
for (int i = 0; (i < [tokensA count] || i < [tokensB count]) && result == NSOrderedSame; i++) {
NSString *tokenA = [tokensA objectAtIndex:i];
NSString *tokenB = [tokensB objectAtIndex:i];
// problem: 8.04.2 is not a number, so we need to tokenize again on .
NSArray *versionTokensA = [tokenA componentsSeparatedByString:#"."];
NSArray *versionTokensB = [tokenB componentsSeparatedByString:#"."];
for (int j = 0; (j < [versionTokensA count] || j < [versionTokensB count]) && result == NSOrderedSame; j++) {
NSString *versionTokenA = [versionTokensA objectAtIndex:j];
NSString *versionTokenB = [versionTokensB objectAtIndex:j];
NSNumber *numberA = [formatter numberFromString:versionTokenA];
NSNumber *numberB = [formatter numberFromString:versionTokenB];
if (numberA && numberB) {
result = [numberA compare:numberB];
} else {
result = [versionTokenA compare:versionTokenB];
}
}
}
[formatter release];
return result;
}