Adding a NSDictionary to a NSArray duplicates the first NSDictionary every time - objective-c

So I pulled some JSON data from a web service which is stored in an NSArray called _infoFromJSON. Each array element in _infoFromJSON essentially has a dictionary of key/value pairs. The goal is to add them to myVehicleObject which is an NSMutableArray
for (NSDictionary* myDictionary in _infoFromJSON) {
myVehicleObject *vehicleInMembersProfile;
vehicleInMembersProfile = [[myVehicleObject alloc] init];
vehicleInMembersProfile.make = [[_infoFromJSON objectAtIndex:carCount] objectForKey:#"make"];
vehicleInMembersProfile.carName = [[_infoFromJSON objectAtIndex:carCount] objectForKey:#"nickname"];
vehicleInMembersProfile.year = [[_infoFromJSON objectAtIndex:carCount] objectForKey:#"year"];
carCount ++;
[self.myVehicleObject addObject:vehicleInMembersProfile] ;
};
With the above code I sort of achieved it, however it keeps adding the same 1st dictionary to myVehicleObject, so it inserts the same NSDictionary 4 times In the past I have used this:
[self.myVehicleObject addObject:[vehicleInMembersProfile copy]] ;
When I do it it throws the following exception:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[myVehicleObject copyWithZone:]: unrecognized selector sent to instance 0xab4e130'
What am I doing wrong here? Thanks!
Update Requested Sample JSON:
{
color = SILVER;
engine = "";
id = "CF270B81-3821-4585-8C90-7089D7A8654E";
imageUrl = "https://www.someprotectedurl.com/somefile.png";
licensePlate = "ABC-123";
make = Honda;
model = "CR-V";
nickname = "My CR-V";
vin = "XX551234687687687654";
year = 2009;
}

This may or may not be related to the problem, but your forin loop is completely broken. Whether or not your incorrect usage is the actual cause of the problem, this is something you should definitely fix as it can do nothing but cause problems.
If you want to use indexOfObject: to grab an object at an index of the array you're iterating through, you should use a regular for loop:
for (int carCount=0; index < [_infoFromJSON count]; ++carCount) {
// loop body remains identical to what you have...
// except remove carCount++;
}
But for what you're doing, a forin loop is indeed better, and forin loops can be faster since they can be handled in batches. But if you're using a forin loop, use the object you're defining in the loop declaration:
for(NSDictionary* myDictionary in _infoFromJSON) {
// myDictionary is a reference to an object in _infoFromJSON,
//for whatever given index it is currently working on
myVehicleObject *vehicleInMembersProfile = [[myVehicleObject alloc] init];
vehicleInMembersProfile.make = myDictionary[#"make"];
vehicleInMembersProfile.carName = myDictionary[#"nickname"];
vehicleInMembersProfile.year = myDictionary[#"year"];
[self.myVehicleObject addObject:vehicleInMembersProfile];
}

The error is that your class does not implement NSCopying.
However, there isn't any need to copy the object here. You're creating a new object each time through the loop. If you insert a copy, you're just pointlessly throwing away the original each time. The more likely cause if you're seeing odd loop behavior is that your loop is mixing up different kinds of enumeration, as pointed out by nhgrif. Instead of accessing [_infoFromJSON objectAtIndex:carCount], just use myDictionary.

I would probably use a for loop rather than a foreach since you need the array index, I would code it like this
NSMutableArray *vehiclesArray = [[NSMutableArray alloc]init];
for (int i = 0; i < [_infoFromJSON count]; i++)
{
//create vehicle
myVehicleObject *vehicleInMembersProfile = [[myVehicleObject alloc] init];
vehicleInMembersProfile.make = _infoFromJSON[i][#"make"];
vehicleInMembersProfile.carName = _infoFromJSON[i][#"nickname"];
vehicleInMembersProfile.year = _infoFromJSON[i][#"year"];
//finally add the vehicle to the array
[vehiclesArray addObject:vehicleInMembersProfile] ;
}
I wasn't sure what myVehicleObject was , and why is it the same type you are adding to itself, so I changed it to an array. But you get the point.

Related

Objective-C create dynamic array names based on 1 piece of info in the array or add to that array if it already exists

Ok here is a challenge before me I am having trouble with:
I need to create multiple arrays in a custom object dynamically
heres the idea a student enters their assignments including class name I want to add it to an array dependent on the class name. This is dynamic so i need to create an array of arrays the main array named for the class name. This allows for unlimited number of classes.
I know how to do this with arrays pre named in my object and to load to these array. I am having trouble figuring out the dynamic creation of these array names.
Any ideas I am stuck.
Like I said, just stuck on where to go next so that it can be assigned to an array of ADP1 or ADP2 and if I add an English assignment it load into an array for English and then if I take Calculus I can add that assignment and it will create a new array to load my calculus assignments into.
solved with this:
for (int i =0; i < [classList.classesArray count]; i++)
{
NSString *classy = [classList.classesArray objectAtIndex:i];
NSMutableArray *classless = [classList.classesArray objectAtIndex:i];
classless = [[NSMutableArray alloc] initWithObjects: nil];
for (int a =0; a < [assignmentList.assignmentsArray count]; a++)
{
if ([educate containsObject:classless])
{
if (classy == [[assignmentList.assignmentsArray objectAtIndex:a] classSched])
{
Assigned *assignments = [assignmentList.assignmentsArray objectAtIndex:a];
[classless addObject: assignments];
}
}
else
{
[educate addObject:classless];
if (classy == [[assignmentList.assignmentsArray objectAtIndex:a] classSched])
{
Assigned *assignments = [assignmentList.assignmentsArray objectAtIndex:a];
[classless addObject: assignments];
}
}
}
}
It sounds like what you want is an NSDictionary. Arrays don't have names, but dictionaries can have arbitrary keys that correspond to objects, which is basically a "name" for the object (since you can ask the dictionary for an object by "name").

What is the most efficient way to move NSArray objects to UITextFields?

I have some code where there may or may not be objects in the Array... this is the code I am dealing with:
oServices1.text = CustomServicesArray[0];
oServices2.text = CustomServicesArray[1];
oServices3.text = CustomServicesArray[2];
oServices4.text = CustomServicesArray[3];
oServices5.text = CustomServicesArray[4];
oServices6.text = CustomServicesArray[5];
oServices7.text = CustomServicesArray[6];
oServices8.text = CustomServicesArray[7];
oServices9.text = CustomServicesArray[8];
oServices10.text = CustomServicesArray[9];
oServices11.text = CustomServicesArray[10];
oServices12.text = CustomServicesArray[11];
oServices13.text = CustomServicesArray[12];
oServices14.text = CustomServicesArray[13];
oServices15.text = CustomServicesArray[14];
oServices16.text = CustomServicesArray[15];
oServices17.text = CustomServicesArray[16];
oServices18.text = CustomServicesArray[17];
oServices19.text = CustomServicesArray[18];
oServices20.text = CustomServicesArray[19];
oServices21.text = CustomServicesArray[20];
oServices22.text = CustomServicesArray[21];
oServices23.text = CustomServicesArray[22];
Rather than check each and every array object for nil, is there a way I can take the oServices*xx*.text UIFields and put them into some kind of array so I can just use a loop?
Are you aware of reflexivity? With KVC you could save up much code and time:
for(int i=1; i<=23; i++) {
NSString* key= [NSString stringWithFormat: #"oServices%d"i];
// Remember that variables should start with a lowercase letter
[[self valueForKey: key] setText: customServicesArray[i-1] ];
}
But if you don't want to bind all these variables in your storyboard/xib file (even this may be too much), just set the tag of each text field in the order that you want (from 1), so that you can get them back using viewWithTag:
// From the UIViewController
for(int i=1; i<=23; i++) { // Consider defining a constant instead of 23
[[self.view viewWithTag: i] setText: customServicesArray[i-1] ];
}
I consider this last solution better because you avoid binding so many variables.
You can use an OutletCollection to hold oServices and loop on that. Note however that outlet collections are not sorted so you would need to sort them beforehand (on the tag criteria, or location for example).
For ordering see this question.
Set the tag property of the UITextFields to their corresponding ordinal in the array. The default value of tag is 0, so you may need to set the tag property to ordinal + 1 if there are other views in the parent view of your UITextFields. On the parent view of your text fields, you can use the viewWithTag: method to retrieve the appropriate UITextField.

objective-c changing array contents inside for loop

I have an issue that (I think) might have to do with scope, but I'm not sure. I'm trying to do something that I think should be simple, but I am getting a strange result, and I could truly use some advice. I would say I'm an early-objective-c programmer, but not a complete newb.
I have written a function in objective-c that I would like to use to change the key-names in a mutable array of mutable dictionary objects. So, I want to pass in a mutable array of mutable dictionary objects, and return the same mutable array with the same dictionary objects, but with some of the key-names changed. Make sense?
I have tried several log statements in this code, which seem to indicate that everything I'm doing is working, except when the for loop is finished executing (when I try to test the values in the temp array), the array appears to contain only the LAST element in the source array, repeated [source count] times. Normally, this would lead me to believe I'm not writing the new values correctly, or not reading them correctly, or even that my NSLog statements aren't showing me what I think they are. But might this be because of scope? Does the array not retain its changes outside of the for loop?
I have put a fair amount of time into this function, and I have exhausted my bag of tricks. Can anyone help out?
-(NSMutableArray *)renameKeysIn:(NSMutableArray*)source {
/*
// Pre:
// The source array is an array of dictionary items.
// This method renames some of the keys in the dictionary elements, to make sorting easier later.
// - "source" is input, method returns a mutable array
*/
// copy of the source array
NSMutableArray *temp = [source mutableCopy];
// a temporary dictionary object:
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
// These arrays are the old field names and the new names
NSMutableArray *originalField = [NSMutableArray arrayWithObjects:#"text", #"created_at",nil];
NSMutableArray *replacedField = [NSMutableArray arrayWithObjects:#"title", #"pubDate", nil];
// loop through the whole array
for (int x =0; x<[temp count]; x++) {
// set the temp dictionary to current element
[dict setDictionary:[temp objectAtIndex:x]];
// loop through the number of keys (fields) we want to replace (created_at, text)... defined in the "originalField" array
for (int i=0; i<[originalField count]; i++)
{
// look through the NSDictionary item (fields in the key list)
// if a key name in the dictionary matches one of the ones to be replaced, then replace it with the new one
if ([dict objectForKey:[originalField objectAtIndex:i]] != nil) {
// add a new key/val pair: the new key *name*, and the old key *value*
[dict setObject:[dict objectForKey:[originalField objectAtIndex:i]]
forKey:[replacedField objectAtIndex:i]];
// remove the old key/value pair
[dict removeObjectForKey:[originalField objectAtIndex:i]];
}// end if dictionary item not null
}// end loop through keys (created_at, text)
[temp replaceObjectAtIndex:x withObject:dict];
}// end loop through array
// check array contents
for (int a=0; a<[temp count]; a++){
NSLog(#"Temp contents: ############ %#",[[temp objectAtIndex:a] objectForKey:#"pubDate"]);
}
return temp;
} // end METHOD
I think the issue is on the line with:
[dict setDictionary:[temp objectAtIndex:x]];
Since these things are almost all working in pointers (instead of copying contents), every element of your temp array will point to the dict dictionary, which is set to be whatever the latest key's dictionary is. I think setting the actual pointer will fix the issue.
dict = [temp objectAtIndex:x];

object inside NSMutableArray is not update immediately after updating

I have a very strange error using NSMutableArray in cocos2d/xcode
In my code, I have a NSMutableArray containing object A
NSMutableArray *peasantArray;
and another NSMutableArray contain object B
NSMutableArray *treeArray;
in the scheduled update function, I called another function which is essentially the following functionality:
I would loop through all the object A inside the *peasantArray, and if any peasant object has a variable var == GameEntityCommandIdling, I would modify the object B in the second NSMutableArray *treeArray,
The issue is that I notice sometimes after I modified the object A inside the peasantArray, the modified variable (var) is being modified/updated inside the object A after by printing out the variable status in a scheduled fashion; but if I am to loop through the NSMutableArray *peasantArray again in the next schedule (1/30s), I will again find the object A with the older/un-updated variable (var), and this is causing my algorithm to be wrong,
However, if I loop through the NSMutableArray *peasantArray less than 1second, each time I would see the variable (var) for object A correctly as the updated variable value,
So is there a limit on how fast I can iterate over the NSMutableArray?
here are some piece of code that I basically just mentioned,
NSMutableArray *peasantArray;
NSMutableArray *treeArray;
.....
peasantArray = [[[NSMutableArray alloc] initWithCapacity:1]retain];
for(int i = 0; i < 1; i++)
{
Peasant *A = [[Peasant alloc] init];
[peasantArray addObject:A];
}
....
//inside the update()
for (int i = 0;i < [peasantArray count];i++)
{
Peasant *A = [peasantArray objectAtIndex:i];
if (A.status == something)
{
printf("A.status is something\n");
A.status = sometingelse;
...
//update other things not related to this NSMutableArray or object
}
}
.....
SO the error is that sometimes I will have multiple printf of "A.status is something", although only one of it should be printed,
I really appreciate any help,
Thanks,
So is there a limit on how fast I can iterate over the NSMutableArray?
Definitely no. That would be the stupidest implementation of an array I'd ever encountered. :)
The simplest explanation is usually the answer. You say the message is printed more than once. Well have you checked that maybe more than one Peasant has its status set to something?
If that's not the case, are you certain the status update is printed twice in the same frame, and not twice in two subsequent updates?
Earlier on you seemed to indicate that the effect of iterating over one array and modifying the other array's objects is invalidated somehow. That made me want to point out that if you have the same object in both arrays, modifying the object's properties in array A will also modify the properties of the same object contained in array B.
You may want to give breakpoints a(nother) try. The problem should be easy to locate when you step through the code.
Here you have a memory leak
for(int i = 0; i < 1; i++)
{
Peasant *A = [[Peasant alloc] init];
[peasantArray addObject:A];
}
you should release A after adding it to the array since the addObject adds a reference count to the object.
for(int i = 0; i < 1; i++)
{
Peasant *A = [[Peasant alloc] init];
[peasantArray addObject:A];
[A release];
}

Need help with NSMutableArray solution

Im currently devising a solution for my object BuildingNode *tower which is held inside NSMutableArray *gameObjects, to attack EnemyNode *enemy objects also held inside the gameObjects array.
I have a proposed solution which occasionally causes my game to freeze (temporarily) as the solution employed is quite buggy.
My solution is that each tower object contains its own NSMutableArray *targets which is synthesized from the Tower Class. If an enemy comes into range or out of range of any given tower object, the corrosponding index of the EnemyNode *enemy object from the gameObjects array is saved as an NSNumber into the targets array, or alternatively if the enemy object is out of range, it is removed from the .targets array.
Basically the idea is that the targets array holds the indices of any enemy that is in scope of the tower.
The problem I seem to be facing is that because this tower.targets array is updated dynamically all the time, i believe that if i'm doing some sort of operation on a particular index of tower.targets that then is removed, i get this error:
-[BuildingNode distance]: unrecognized selector sent to instance 0x2dd140
Each BuildingNode *tower has different attacking alogrithms that use the tower.targets array for calling back the sorted/desired enemy.
For example, a random attack style will randomize a number between 0 & [tower.targets count] then I can create a pointer to gameObjects with the corresponding [tower.targets intValue].
Something like this:
EnemyNode *enemy = (EnemyNode *)[gameObjects objectAtIndex:[[tower.targets objectAtIndex:rand]intValue]];
So this will find a random enemy from the potential .targets array and then create a pointer object to an enemy.
I've put in many if statements to ensure that in the case of a .targets index being removed mid-sorting, the operation shouldnt go ahead, thus removing the game failure rate, but it still occurs occassionally.
Heres my code:
Please note that BuildingNode *tower == BuildingNode *build.
This is just a snippet of the iteration inside gameObjects.
//Potential Enemies (Indices) Add and Delete/
if (enemy.distance < build.atk_distance && !enemy.isExploding){
NSNumber *index = [NSNumber numberWithInt:[array indexOfObject:enemy]];
if(![build.targets containsObject:index]){
[build.targets addObject:index];
}
}
else {
NSNumber *index = [NSNumber numberWithInt:[array indexOfObject:enemy]];
if ([build.targets containsObject:index]){
[build.targets removeObject:index];
}
}
}
//Aiming// Nearest Algorithm.
//Will find the nearest enemy to the building
if (enemy.distance < build.atk_distance){
if (!build.isAttacking || build.atk_id == 0){
if ([build.targets count]){
if ([build.atk_style isEqualToString:#"near"]){
int l_dist;
for (int i = 0; i < [build.targets count]; i++){
//Grab the Enemy from Targets
if ([build.targets objectAtIndex:i]){
if([array objectAtIndex:[[build.targets objectAtIndex:i]intValue]]){
EnemyNode *temp = [array objectAtIndex:[[build.targets objectAtIndex:i]intValue]];
if (temp){
int c_dist = temp.distance;
if (!l_dist || c_dist < l_dist){
l_dist = c_dist;
build.atk_id = temp.uniqueID;
build.isAttacking = YES;
}
}
}
}
}
}
}}
Unrecognized selector sent = calling a method on an object that doesn't exist. In this case, you're calling the distance method/property getter on a BuildingNode object.
The only distance I see is on your temp object, which is retrieved by EnemyNode *temp = [array objectAtIndex:[[build.targets objectAtIndex:i]intValue]]; That indicates you are really pulling a BuildingNode object out of the array instead of an EnemyNode. Find out why that happens.