Only the last value of NSMutableDictionary is added to NSMutableArray - iphone

I have tried my best to search for the answers to add NSMutableDictionary to NSMutableArray. Unfortunately, they all asked me to use "[allValues]" which is not what I want.
Here is the issue,
In the header file, I defined,
NSMutableArray *arData;
And in the m file,
arData = [[NSMutableArray alloc] init];
NSMutableDictionary *mutableDictionary5 = [[NSMutableDictionary alloc]init];
for (i=0;i<[[[self rssParser]rssItems]count];i++)
{
Lat = [[[[[self rssParser]rssItems]objectAtIndex:i]lat] doubleValue];
Lng = [[[[[self rssParser]rssItems]objectAtIndex:i]lng] doubleValue];
// Creates a marker in the center of the map.
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(Lat, Lng);
marker.title = [[[[self rssParser]rssItems]objectAtIndex:i]header];
[mutableDictionary5 setObject:marker.title forKey:#"title"];
[arData setValue:[mutableDictionary5 valueForKey:#"title"] forKey:#"title"];
}
The "arData" only gets the last value of [[[[self rssParser]rssItems]objectAtIndex:i]header].And I am sure mutableDictionary5 gets all the value since I have put the following at the end of the code,
NSLog(#"mutableDictionary5 values=%#",[mutableDictionary5 allValues]);
It prints all the value of the title.
I understand it shouldn't be setvalue, however, I tried to use [mutableDictionary5 allValues], "addobjects", "allkeys". They are not working. What should I do to let the NSMutableArray arData to add all values of title with "title" as the key? thanks.
Sorry for my bad English which is not my native language.

You erroneously use setValue instead of addObject.
[arData addObject:mutableDictionary5];
This will work if you alloc init a new dictionary inside the loop.
If you want to reduce the array to just titles do this after the loop:
NSArray *titleArray = [arData valueForKeyPath:#"title"];
Now you have an array containing just titles.
BTW, you could make some effort to invent better variable names. Note that by convention in Objective-C variable names start with low cap while class names are capitalized.

Related

NSDictionary won't write to plist

I'm trying to write an NSDictionary with a complex structure to a plist for use in an iPhone app. However, the file doesn't seem to write at all, and I have no idea why.
This is what the structure should look like:
Level Dict
Roads Array
Road1 Array
Vertex1 Dict
x Number
y Number
Vertex2 Dict
...
And this is what my code looks like:
NSMutableDictionary *levels = [[NSMutableDictionary alloc] init];
NSMutableArray *roads = [[NSMutableArray alloc] init];
for(ChainLinkRoad *r in data.roads){
NSMutableArray *road = [[NSMutableArray alloc] init];
for(ChainPoint *p in r.v){
NSNumber *x = [NSNumber numberWithFloat: p.x];
NSNumber *y = [NSNumber numberWithFloat: p.y];
NSMutableDictionary *vertex = [[NSMutableDictionary alloc] init];
[vertex setObject:x forKey:#"x"];
[vertex setObject:y forKey:#"y"];
[road addObject:vertex];
}
[roads addObject:road];
}
[levels setObject:roads forKey:#"Roads"];
bool b = [levels writeToFile:#"test.plist" atomically:YES];
//returns true
I've tried converting the mutables to their immutable counterparts, but that didn't work. I'm able to access data from the final NSDictionary (levels) just fine.
Edit: I should add that this plist is not for actual use in the iphone game. It's for personal use when designing levels. The code won't exist in the final version.
A common problem is, that the dictionary isnt valid for string transformation like invalid UTF-8 characters. Make a output on the console to check it.
If that doesnt help you, save only some elements to see what is going on.
I just posted an answer for this same issue yesterday. Instead of trying to save out the individual data elements of a class save the entire object using NSKeyArchiver and NSCoding. Click the link for a full explanation.
How can I save Array of Class Objects in to a Plist(Iphone Development)

Convert NSString to fetch synthesized information

//COPY THIS CODE IN A FRESH PROJECT!!!
//THIS 2 LINES ARE JUST EXAMPLES, OF VALUES PUSHES OUT A DATABASE
NSString *messagelevel1 = #"45";
NSString *currentlevel = #"1";
NSString *HuidigLevel = currentlevel;
NSDecimalNumber *huidigleveldec = [[NSDecimalNumber alloc] initWithString: HuidigLevel];
float HuidigLevelRek = [huidigleveldec floatValue];
//HERE IS THE PROBLEM
NSString* LevelTotaal=[[NSString alloc] initWithFormat:#"messagelevel%.f",HuidigLevelRek];
NSString*result = LevelTotaal;
NSLog(#"%#",result);
// THE ABOVE RESULT SHOULD RETURN THE SAME VALUE AS THE NEXT (messagelevel1) LINE BUT IT RETURNS ONLY "messagelevel1" AND NOT THE VALUE!
NSLog(#"%#",messagelevel1);
I want the *result string behaves like the *huidiglevel string and fetch some information, but because the LevelTotaal is a NSString, It doesn't fetch this information. I really got no idea where to google for this problem, searching the Developer docs didn't helped either . Maybe you guys can help me out?
Actually the second NSLog returns the value and to first NSLog just returns messagelevel1. To tell you in short ;)
I hope you guys get what I'm saying!
I think what you're trying to do is use variable variables, a system that does not exist in Objective-C. In PHP, you can use variable variables:
$hello = 'abcdef';
$varName = 'hello';
print $$varName; // prints the value of $hello, which is 'abcdef'
Like many things in PHP, this is not really a good way to design software. Instead, consider using something like a NSDictionary, this allows you to give specific data a key.
NSMutableDictionary *aDict = [NSMutableDictionary dictionary];
[aDict setObject:[NSNumber numberWithFloat:4.5] forKey:#"messageLevel1"];
NSString *result = [aDict objectForKey:#"messageLevel1"];
You can obtain the data dynamically, the key can be generated or obtained at runtime.
Edit:
Rather than having variables called messageLevel1, messageLevel2, messageLevel3 ... messageLeveln, just use an array.
NSMutableArray *messageLevels = [NSMutableArray array];
[messageLevels addObject:#"1"];
[messageLevels addObject:#"45"];
[messageLevels addObject:#"123"];
NSString *result = [messageLevels objectAtIndex:HuidigLevelRek];

Creating a Two-Dimensional Array with Concrete Positions

I need to create a custom array:
In php I would define as follows:
$myarray[100][80] = 1;
But I don't know how to do it in objective-c...
I don't need an array [0][0],[0][1],[0][2], ... I only need concrete positions in this array [80][12], [147][444], [46][9823746],...
The content of these positions always will be = 1;
for this you would use a dictionary rather than an array as they are always 0,1,2 keyed so something along the lines of:
NSNumber *one = [NSNumber numberWithInt:1];
NSString *key = #"80,12";
NSDictionary *items = [NSDictionary dictionaryWithObject:one forKey:key];
Then to pull them out again you would use the objectForKey: method.
You cannot put ints directly into arrays or dictionaries that's why it is wrapped in the NSNumber object. To access the int after getting the NSNumber out of the dictionary you would use something like:
NSNumber tempNum = [items objectForKey:key];
int i = tempNum.intValue;
See the docs here for a full explanation of the NSDictionary class. Hope this helps...
I an not a PHP master but I believe in php arrays are not real arrays they are hash tables right?
Anyway, I think you are looking for NSDictionary or NSMutableDictionary class.
That looks more like a bitset than an array.
Allocating so many cells for that seems useless, so maybe you could revert the problem, and store the positions in an array.
Well in objective c we can use NSMutableArray to define 2-D arrays.
See the following code, it might help you
NSMutableArray *row = [[NSMutableArray alloc] initWithObjects:#"1", #"2", nil];
NSMutableArray *col = [[NSMutableArray alloc] init];
[col addObject:row];
NSString *obj = [[col objectAtIndex:0] objectAtIndex:0];
NSLog(#"%#", obj);

Refresh Value in NSMutableDictionary using ViewWillAppear

See this code:
int i = years;
NSLog(#"Years i: %i",i);
NSString *syears= [NSString stringWithFormat:#"%d",i];
menuList = [[NSMutableArray alloc] init];
[menuList addObject:[NSMutableDictionary
dictionaryWithObjectsAndKeys:
#"years", kLeftKey,
syears, kRightKey, nil, kControllerKey, nil]];
The above is an extract from ViewWillAppear. When I switch between tabs ViewWillAppear is doing it's job and the data is updating down as far as NSString *syears= [NSString stringWithFormat:#"%d",i]; but after that my array doesn't get updated with the latest value of syears. I tried using setObject and setValue but these don't work with NSMutableArray. Any ideas?
Keys and values in NSDictionary need to be non-nil NSObjects. So you've definitely got an issue with a nil in there, and there may be a question about kLeftKey et al, for which you haven't shown the definitions.
More generally, it would help to know what you are doing with menuList and what you mean by "my array doesn't get updated". Are you trying to display it? Using it as a data source somewhere? You are creating the array anew here -- could a previous reference be being left around and displayed?

Creating Objects & Setting iVars in a Loop?

NSArray *planetArray = [NSArray arrayWithObjects:#"Earth",
#"Jupiter",
#"Saturn",
#"Neptune",
#"Pluto", nil];
NSMutableArray *objectArray = [[NSMutableArray alloc] init];
for(NSString *eachPlanet in planetArray) {
Planet *newPlanet = [[Planet alloc] init];
[newPlanet setValue:eachPlanet forKey:#"name"];
[newPlanet setValue:#"TEST" forKey:#"type"];
[newPlanet setValue:[NSNumber numberWithInt:1234] forKey:#"mass"];
[objectArray addObject:newPlanet];
[newPlanet release];
}
for(Planet *displayEachPlanet in objectArray) {
NSLog(#"DATA: %#", displayEachPlanet);
}
[objectArray release];
I am curious if this is the best way to create an object and set an iVar for each item in an array. Basically I am:
Creating a Planet object
Setting the iVar (from the NSString array)
Adding the Planet object to an array.
Releasing the Planet object
Printing my Planet objects
Releasing the array
NB: I am just testing, this is not for anything, I was just curious ...
cheers Gary
Can't see anything drastically wrong about doing it that way. One suggestion would be to have an extended initialiser for your planet class, along the lines of:
-(Planet*) initWithName:(NSString*)name andType:(NSString*)type withMass:(int)mass;
And then create the planet with:
Planet *newPlanet = [[Planet alloc] initWithName:eachPlanet andType:#"Test" withMass:42];
Looks good to me. If all you are doing with the objects is printing something from them, you could probably do it in one loop with less initializing and such, but if thats just a test..it looks fine.