Object becomes duplicated in NSMutableArray - ios

Im trying to add an object to NSMutableArray it seems to get duplicated.
#interface TestObject : NSObject {
double a_actual;
double a_target;
}
#property(assign) double a_actual;
#property(assign) double a_target;
Create some pointers:
NSMutableArray * myTestObjectArray;
TestObject * myTestObject;
Init them:
myTestObjectArray = [[NSMutableArray alloc] init];
myTestObject = [[TestObject alloc] init];
I add value to the object and add it to the array:
[myTestObject setA_actual:234];
[myJointDataArray insertObject:myTestObject];
I add different values to each object, but i do not necessarily fill all the variables out.
When i print each object out i have the same (last) value duplicated in all objects for some reason.
Printing the array shows that all objects are the same:
Array: (
"<TestObject: 0x6b9b400>",
"<TestObject: 0x6b9b400>",
"<TestObject: 0x6b9b400>",
"<TestObject: 0x6b9b400>",
"<TestObject: 0x6b9b400>",
"<TestObject: 0x6b9b400>" )
Should i alloc a new object of TestObject everytime i want to work with a new?

Should i alloc a new object of TestObject everytime i want to work with a new?
Yes. If you don't allocate a new object, you're just working with the same object over and over again. It appears you want multiple, distinct objects, so allocate a new instance for each one.

To make it more clear to you why it is failing, consider that insertObject: takes a pointer to an object as a parameter. So when you send the insertObject: message to your array, it will store a pointer to that object, not a copy of the object itself. That's why you have to alloc/init a new instance of it.

You are basically adding the same object. If you check the value of "a_actual" for each object inside your array, you will see it's the same. You should allocate a new one and add it.

Related

add new object to nsmutablearray replace all objects in array

i try to add new object to my nsmutablearray but every time it replace all object
-(void)addToStack:(Coordinate *)coord{
Coordinate*c = [[Coordinate alloc] init];
c.x=coord.x;
c.y = coord.y;
if (coord.x==0 && coord.y==0) {
c.x=coord.x+1;
[_stack addObject:c];
c.x=coord.x;
c.y=coord.y+1;
[_stack addObject:c];
c.y=coord.y;
}
}
You are not adding a new object but you are changing the old object where the reference will remain the same.
NSMutableArray addObject will not add it because it already exists in the array.
So, when trying to add a new object, first create a copy of the one that you want to change, like this:
Coordinate *newCoordinate = [Coordinate mutableCopy];
// change attributes
// add it to the array
Everybody who said that adding the same object twice deletes the first instance and replaces it, is wrong.
Arrays can contain duplicate references to the same object. However, it's more like saving the same street address in an rolodex twice. If you look up the address in the first entry, go break all the windows in that house, then go back, look up the address in the second slot in your rolodex, and drive to THAT address, you'll find the house has broken windows (Because both addresses point to the same house.)
Similarly, when you add the same object to an array twice, it's two pointers to the same object. When you change values of the object at index 0, you see those changes reflected in the object in index 1 because it's a second pointer to the same object.
Despite saying the wrong thing about what goes wrong with your code, #Shashi3456643 gave you the correct solution, which is to create a new, unique object for every entry in your array.
Make sure to initiate the array:
NSMutableArray *stack=[[NSMutableArray alloc] init];
This is because every time you init the array. Initialize the array once.
For example:
in .h
Coordinate*c;
in .m
- (void)viewDidLoad
{
c = [[Coordinate alloc] init];
}
-(void)addToStack:(Coordinate *)coord{
c.x=coord.x;
c.y = coord.y;
if (coord.x==0 && coord.y==0) {
c.x=coord.x+1;
[_stack addObject:c];
c.x=coord.x;
c.y=coord.y+1;
[_stack addObject:c];
c.y=coord.y;
}
}

NSMutableArray Extra Nil Sentinels

I've read a text file into an array of strings. In the below code I'm creating objects from that array and adding them into an NSMutableArray.
NSMutableArray* metaphors = [[NSMutableArray alloc] init];
unsigned int i, cnt = [allLinedStrings count];
for(i = 0; i < cnt-3; i+=5)
{
Metaphor *newMetaphor = [[Metaphor alloc] init];
[newMetaphor setMetaphorTitle: allLinedStrings[i]];
[newMetaphor setCorrectAnswer: allLinedStrings[i+1]];
[newMetaphor setLiteralAnswer: allLinedStrings[i+2]];
[newMetaphor setWayOffAnswer: allLinedStrings[i+3]];
[metaphors addObject:newMetaphor];
}
As for the problem, when I access any item via index ([metaphors objectAtIndex:3] for example) every other element (odd numbered ones) are nil elements. All of the objects are added to the array, though. My guess is that addObject is adding an element to the array as well as a new nil sentinel every time? Should this be happening/should I manually go through and remove these elements?
Also a side note, as I'm new to Objective-C, my Metaphor class contains the 4 instance fields you can see within the body: I'm sure there is quicker syntax to initialize one of these objects if anyone could point me the right way. Thanks.
NSArray can't contain nil. It's invalid. If you are getting nil back in a call to an array, the array pointer itself is almost certainly nil. (You CAN send messages to a nil object pointer in Objective C. It simply returns nil/zero.)
Trying to add a nil to an NSArray will cause a crash, and trying to index past the end of an NSArray will also crash.
There is a special class NSNull that provides a singleton placeholder object that can take the place of a nil entry in an NSArray.
The nil sentinel is only a way to know the last element of a variable length array has been reached. The nil sentinel ISN'T added to the NSMutableArray;
NSMutableArray addObject method doesn't need a nil sentinel as you only add ONE object, not a variable length array.
If you need to add something "nil" to an array, you might use [NSNull null] which is an object "equivalent to nil".

NSArray mutableCopy creates new array but still points to old contents

I have an NSMutableArray called playersArray in my singleton class which holds for my applications main datasource.
Each object of playersArray is a NSDictionary and the content is like :
{
sgfID = 1;
sgfPlayer = "<PlayerContact: 0xbf851b0>";
}
PlayerContact is a NSObject subclass containing properties like:
NSString * playerName, playerTeam, BOOL PlayerSelected and so on.
In one of my ViewControllers, in viewDidLoad, I want to take a deep copy of playersArray in to a NSMutableArray named duplicatePlayersArray. I do this by
playersArray = [[SGFHelper sharedHelpers] SGFContactsArray];
duplicatePlayersArray = [playersArray mutableCopy];
Now that I have two separate copies, I was under the impression that playersArray and duplicatePlayersArray are two totally different arrays in the memory. However I found that they are NOT!
Even if the debugger shows that they have different memory addresses, their contents have same memory addresses. So when i do this:
[((NSMutableDictionary *)[duplicatePlayersArray objectAtIndex:0]) setObject:#"333" forKey:#"sgfID"];
playersArray's dictionary at index:0 has ALSO "333" as key "sgfID" instead of "1" as it used to before the above line of code ran.
BUT, if I run the below code, only then, the two arrays start to differ
[duplicatePlayersArray replaceObjectAtIndex:0 withObject:tempDict];
Still this doesn't address my concern because the two arrays which I wanted to believe are different are still "connected". A change in one, results in the other array to change its contents.
Can you friends please show me a way to DEEP COPY the array I explained the contents of in a way where all of their contents are kept in different objects.
Use initWithArray:copyItems: to copy each entry in the array
NSMutableArray *duplicatePlayersArray = [[NSMutableArray alloc] initWithArray:playersArray copyItems:YES];

NSMutableArray replacing object insted of adding

I'm using a NSMutableArray to store an object called poligonon. This object has a NSMutableArray as property to store coordinates X.
But when I add the second object, the first object on the array transform itself. All objects on the array must be differents, but they are equal the last object in the array.
Exemple:
coordArrayX is a property (NSMutableArray)
-saveDataIntoArray
{
poligonon.coorArrayX = coordArrayX;
arrayPoligonon addObject: poligonon;
}
The first time that the user clicks to save, the first coordinate is 74.
Now, he creates a new poligonon that has coordinate 45, and add to the array.
When the user checks, the first poligonon has coordinate = 45.
How to solve?
Each and every time you are adding the same poligonon to the array and overwriting the value of coorArrayX.
Instead of,
{
poligonon.coorArrayX = coordArrayX;
arrayPoligonon addObject: poligonon;
}
Try this,
{
poligonon = [[Poligonon alloc] init];
poligonon.coorArrayX = coordArrayX;
[arrayPoligonon addObject:poligonon];
}

C-style array of pointers to Objective-C objects under ARC

I have a 2D array of pointers to Objective-C instances to keep track of game objects on a map grid.
Now I am transitioning my code to ARC, and Xcode pointed the error. I knew pointers to objects aren't allowed as struct members, but this one caught me (almost) off guard.
I understand the rationale behind the ARC constrains, but:
I can't afford the overhead of objective-C arrays when looking up objects in the grid, and
The objects themselves are already owned by an NSArray ivar defined in the same class that has the C-style grid as an ivar; the c-style array is only a conveniently structured shortcut. Futhermore, when objects are removed from the owning NSArray, I set the corresponding grid slot to NULL.
That is, the 2D array (grid) is just a collection of fast (but dumb) pointers to objects safely retained somewhere else (the NSArray ivar).
Is there a way to get away with this using casts? For example, define and alloc my grid as:
void*** _grid;
instead of
MyMapObjectClass*** _grid
and use (appropriately bridged) casts between void* <-> MyMapObjectClass* when setting or getting the pointers in each slot?
EDIT: So here is how I solved it
I changed the ivar declaration as described above. In addition, when setting an entry of my look-up grid, I did this:
// (Done **Only Once** at map initialization)
// _objectArray is an instance of NSMutableArray
MyMapObjectClass* mapObject = [[MyMapObjectClass alloc] init];
// ...configure map object, etc...
// Add to Obj-C array:
[_objectArray addObject:mapObject];
// Add pointer to 2D C array:
_grid[i][j] = (__bridge void*)mapObject;
When accessing the object at (x,y), I do the opposite:
MyMapObjectClass* object = (__bridge MyMapObjectClass*) _grid[x][y];
[object performSomeMethod];
// etc...
When removing the object from the map, I do this:
MyMapObjectClass* object = (__bridge MyMapObjectClass*) _grid[x][y];
[_objectArray removeObject:object];
_grid[x][y] = NULL;
Map objects are created once at the beginning of the game, and removed according to game progress. If I need to replace a map object for another, I would do this:
MyMapObjectClass* oldObject = (__bridge MyMapObjectClass*) _grid[x][y];
// (should mark as weak?)
[_objectArray removeObject:oldObject];
_grid[x][y] = NULL;
MyMapObjectClass* newObject = [[MyMapObjectClass alloc] init];
[_objectArray addObject:newObject];
_grid[x][y] = (__bridge void*)newObject;
Circumventing ARC using casts is generally a bad idea. The better way would be to disable ARC for your map.m (or break out just the lookup part into a separate class).Then do manual memory management inside it with retain / release and the C structures you like, as long as you do it correctly it will work fine and you will be able to call it from other classes, avoiding the overhead of nested NSArrays etc..

Resources