Cocos2d/iOS: can't understand how to interpet a pointer address - ios

I have a NSMutableArray containing 200 bullets (sublcass of CCSprite) created as following:
capacity=200;
bullets = [[NSMutableArray alloc] initWithCapacity:capacity];
// Create a number of bullets up front and re-use them whenever necessary.
for (int i = 0; i < capacity; i++)
{
Bullet* bullet = [Bullet bulletWithScreenRect:screenRect];
bullet.visible = NO;
bullet.bulletId=i;
[bullets addObject:bullet];
[self addChild:bullet];
}
I created a for loop to iterate them and added a breakpoint to see if the address was the same.
for (int i = 0; i < capacity; i++)
{
Bullet* bullet = [bullets objectAtIndex:i];
CCLOG(#"%i %i", i, bullet.bulletId);
}
The result is that the pointer "bullet" always refers to the same address in memory for all 200 bullets (0x1336c8a0). I added a property in bullet (int:bulletId) to try identify if they are different objects or not but it seems so. I don't understand why the pointer has always to the same address (does it refer to the same address? or is it just the pointer memory address?).
Here is where I get the 0x1336c8a0 address from the Bullet* pointer:

I would look in the bulletWithScreenRect method of the Bullet class. I assume this is a factory method, but maybe it just returns the same static object. You could alloc and init the Bullet object yourself, and then I assume there is a way to set the screen rectangle separately.
In other words, change:
Bullet* bullet = [Bullet bulletWithScreenRect:screenRect];
To something like this:
Bullet* bullet = [[Bullet alloc] init];
bullet.screenRect = screenRect; // Not sure if this setter is present.
At the very least, just for a sanity check you can change the constructor of the Bullet class, to ensure you are creating separate instances. Like I said, check the contents of the bulletWithScreenRect method to see what it is really doing. That seems like the culprit to me.

Well that means that you only have one instance of Bullet in your array. In that case, your problem is definitely in your bulletWithScreenRect method, which returns a cached instance instead of a new one.
The address you're seeing the debugger is the address to which the pointer is pointing not the address of the pointer, which would be more or less useless. Since the address to which the pointer is pointing is always the same, it's clear that we're talking about the same object.
To test what I've just said, you could print the address and compare it to the value you get in the debugger:
NSLog(#"Pointer own address: %p", &bullet);
NSLog(#"Address to where the pointer is pointing: %p", bullet); //this is what you should get in the debugger

Related

If NSString is class and it is passed by reference then why is this output? [duplicate]

I have a simple question. If I am declaring NSString (ref type) as shown below:
NSString *johnsMoney = #"200";
NSString *marysMoney = johnsMoney;
NSLog(#"Johns Money %#",johnsMoney);
NSLog(#"Marys Money %#",marysMoney);
johnsMoney = #"100";
NSLog(#"Johns Money %#",johnsMoney);
NSLog(#"Marys Money %#",marysMoney);
The output produced is this:
Johns Money 200
Marys Money 200
Johns Money 100
Marys Money 200
From my understanding when I assign #"100" to johnsMoney should it not also change the value of "marysMoney" to 100 since marysMoney is pointing to johnsMoney.
UPDATE:
I believe the following example shows what I initially was trying to do:
Dog *dog1 = [[Dog alloc] init];
dog1.name = #"Dog 1";
Dog *dog2 = dog1;
NSLog(#"Dog 1 %#",dog1.name);
NSLog(#"Dog 2 %#",dog2.name);
dog1.name = #"Dog 3";
NSLog(#"Dog 1 %#",dog1.name);
NSLog(#"Dog 2 %#",dog2.name);
johnsMoney and marysMoney are both pointers to strings.
When you write johnsMoney = #"100", it now points to a different string. This doesn't change marysMoney which still points to the original string.
If you were using NSMutableString, and you did [johnsMoney setString:#"100"], then it would change the underlying data (to which both variables would still be pointing).
They are not references. They are object pointers. If two variables happen to point to the same object, changing one pointer to point to another object has no effect on the other pointer.
Think of two people standing near each other. Both hold out an arm and point to the same table. Now one person turns and points to a chair. The other person isn't affected. They are still pointing to the table.
No. Remember you are dealing with pointers. So when you do
johnsMoney = #"100";
You are setting the johnsMoney pointer to a different memory address which contains the #"100" value. marysMoney still points to the original address with the #"200" value.
In your example the local variable marysMoney maintains a strong reference to the initial johnsMoney object. When the johnsMoney property is changed, the property no longer keeps a strong reference to the original value, but that value is still kept alive by the marysMoney strong variable.
#"200" is objective-c notation for an NSString object. It will have it's own memory space and johnsmoney will point to it. So, marysmoney never really points to johnsmoney.
What actually happens is this...
Johns Money 200 // pointer 1
Marys Money 200 // pointer 1
Johns Money 100 // pointer 2
Marys Money 200 // pointer 1
johnsmoney points to #"200". marysmoney also points to #"200". When johnsmoney gets assigned #"100", johnsmoney points to #"100". While marysmoney still points to #"200".
suppose the string :
#"200" pointer address : 0xeeff
#"100" pointer address : 0xeeaa
so ,your code may change like these:
NSString *johnsMoney = #"200";
(johnsMoney = 0xeeff)
NSString *marysMoney = johnsMoney;
(marysMoney = 0xeeff)
johnsMoney = #"100";
(johnsMoney = 0xeeaa)
(marysMoney = 0xeeff)
marysMoney pointer address not changed,but johnsMoney pointer address changed.
As the same:
suppose the object :
dog1 pointer address : 0xeeff
so ,your code may change like these:
Dog *dog1 = [[Dog alloc] init];
(dog1 pointer address: 0xeeff)
dog1.name = #"Dog 1";
Dog *dog2 = dog1;
(dog2 pointer address: 0xeeff)
dog1.name = #"Dog 3";
(dog1 pointer address still: 0xeeff)
(dog2 pointer address still: 0xeeff)
As they all point to the same address,they both changed。
in simply.
NSString *johnsMoney = #"200";
//here johnsMoney is declared as NSString, so it will be string type.
//any thing given inside #"" will be considered as string.
//currently, johnsMoney contains 200.
NSString *marysMoney = johnsMoney;
//here marysMoney is declared as NSString, so it will be string type.
//johnsMoney is already a string. therefore, marysMoney automatically reads the
//string in johnsMoney. so currently, marysMoney will also be 200.
NSLog(#"Johns Money %#",johnsMoney);
NSLog(#"Marys Money %#",marysMoney);
//both will be printed as 200. right?
johnsMoney = #"100";
//now johnsMoney reassigned as 100.
//but still marysMoney is 200.
//there is nothing written for changing maryMoney from 200.
NSLog(#"Johns Money %#",johnsMoney);
NSLog(#"Marys Money %#",marysMoney);
so i think you've got it. i don't want to think it in a complicated manner by including the pointers.
Note:if any one feels that it is rubbish, kindly please avoid my answer. am sorry to post it. i just only vomited the pointer concept. i don't know how much correct is my answer.
NSString is value type. (Immutable).
And there is a concept of sting iterning as well.
NSString *johnsMoney = #"200";
NSString *marysMoney = johnsMoney;
johnsMoney = #"100";
So when you are changing the string of johnsMoney, its now pointing to new memory address. But marysMoney still having old sting (i.e. 200) so pointing to previous address.
Go to this tutorial, you will learn really new things.
https://nshipster.com/equality/

NSMutableArray Interaction Troubles With Collisions

I am having trouble getting objects added to my NSMutableArray to log properly (which definitely means they won't process any of the appropriate functions correctly) with Spritebuilder [version 1.4.9, from the Apple App Store]. I am creating several objects using the same class, but each new one is overriding the older objects which exist. I thought an array would help keep things in order (and then on collision, I could call the array to check for which object was collided with), but it simply is not working that way - at all. Here is the relevant code.
Main.h
#property Coven *coven;
#property Nellie *nellie;
#property NSMutableArray *array;
//Physics, other things
Main.m
/Adding other things...
-(void) addCovenMember{
//This function is called on a RANDOM time interval
_array = [[NSMutableArray] alloc]init];
for (i = 0, i < 15, i++){
_coven = (Coven*) [CCBReader load:#"CovenMember"];
[_array addChild:_coven];
}
[_physicNode addChild:_coven];
}
-(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair nellie:(Nellie*)nellie coven:(Coven*)coven{
for (_coven in _array){
NSLog(#"%#",_coven.name)
if (CGRectIntersectsRect(_nellie.boundingBox, _coven.boundingBox){
NSLog(#"We're intersecting!");
}
}
Coven. h
//Nothing Important Here
Coven.m
-(void)didLoadFromCCB{
self.physicsBody.CollisionType = #"coven";
}
Nellie.h
//Nothing Here
Nellie.m
-(void) didLoadFromCCB{
self.physicsBody.CollisionType = #"nellie";
}
The collision is logging with every collision - but only as the name of the LATEST _coven member to be generated, no matter what I am colliding with. This also means that the _coven.boundingBox is solely on the latest _coven member and interaction only occurs when I hit the new member as soon as it generates on to the screen.
Any ideas? Any help?
Note: This is also posted on the Spritebuilder website - I decided to post it here as well because answers can be a little slow on those forums.
The -(void) addCovenMember overwrites (creates a new instance) of _array every time it's called. Thus, when you try to iterate in -ccPhysicsCollisionBegin: you'll only ever see 1 coven.
Add a nil check around your array creation:
if(_array == nil) {
_array = [[NSMutableArray] alloc]init];
}
The for loop in the -addCovenMember method looks broken (at least not a c loop). Reaplace the , with ;:
for (i = 0; i < 15 i++){
Also, using for(_coven in _array) seems wrong, you already have a property self.coven (presumably) with a backing _coven ivar. Try changing it to for(Coven * c in self.array) and use the local c in the loop:
for (Coven * c in _array){
NSLog(#"%#",c.name)
if (CGRectIntersectsRect(_nellie.boundingBox, c.boundingBox){
NSLog(#"We're intersecting!");
}
}
To everyone out in the world struggling with their ccPhysicsCollisions, arrays may not be the answer - this was a simple fix that left me incapacitated for days.
Using the basic ccPhysicsCollisionsBegan that ships with spritebuilder, try this without arrays first:
Scene.m
-(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair nellie:(Nellie*)nellie coven:(Coven*)coven{
[_coven stopAction:coven.path];
}
I initially created the method with:
[_coven stopAction:_coven.path];
Yes, that (underscore) set me back three weeks. Be sure you refer to the object interacting through the physics delegate, and not the object itself, which in my case, was constantly being overwritten by the new ones being generated.
Check your underscores.
Solved! :D
Thanks to #thelaws for your help! I'll get better at Obj C... eventually.

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;
}
}

Get value from an array of objects in iOS

I am newly to iphone. I am working on an application where we need to calculate the value from an array of objects.
I have created a NSObject class "Catalogue", which includes catalogue_Value and catalogue_quantity. Now, suppose if we have two catalogue object in my array, then i need to calculate the total value.
here is my code :
int initialTotalPoints = 9999;
int totalUsedPoints = 0;
for (int i = 0; i<[arrayCheckout count];i++)
{
Catalogue *catalog = [[Catalogue alloc] init];
catalog = [arrayCheckout objectAtIndex:i];
NSLog(#"checkout voucher %d is = %d*%d", i, catalog.catalogue_Value,catalog.catalogue_quantity);
totalUsedPoints = catalog.catalogue_Value * catalog.catalogue_quantity;
}
initialTotalPoints = initialTotalPoints-totalUsedPoints;
The problem is due to the for loop, always it is taking "totalUsedPoints" of my last array object. But in actually, i need to add "catalog.catalogue_Value,catalog.catalogue_quantity" in my "totalUsedPoints" as per my total array objects. Please help me to solve this problem. Thanks!
If you just want to sum up quantity*value per catalog
int totalPoints = 0;
for (int i = 0; i<[arrayCheckout count];i++) {
Catalogue *catalog = [arrayCheckout objectAtIndex:i];
totalPoints += catalog.catalogue_Value * catalog.catalogue_quantity;
}
// totalPoints is now the sum of each arrays catalogue_Value*catalogue_quantity
You could check out Blockskit, a nice package to make array iterations easier
There is nothing specific to objective c here. Every loop you are overwriting totalUsedPoints with a new value. You then do nothing with it, and it gets overwritten again. At the end of the loop it will only contain the last value assigned to it.
I think what you are looking for is:
totalUsedPoints += catalog.catalogue_Value * catalog.catalogue_quantity;
+= is equal to:
totalUsedPoints = totalUsedPoints + catalog.catalogue_Value * catalog.catalogue_quantity;
meaning it will be assigned with the previous value, plus the new value
This is computer science 101 stuff, not unique to Objective-C. Others have already posted info on what you were doing wrong and how to fix it. I wanted to point out another flaw in your code. Take a look at these 2 lines:
Catalogue *catalog = [[Catalogue alloc] init];
catalog = [arrayCheckout objectAtIndex:i];
In the first line you create a new, empty Catalogue object and save a pointer to it in the variable catalog. In the very next line you fetch an object from your arrayCheckout object and save a pointer to it in your catalog variable. You end up discarding the object you created one line before.
This is like building a brand new car, putting it in front of your house, then junking it and fetching an existing car from a numbered parking space in a parking lot.
In ARC the empty Catalogue object you create in the first object will get deallocated on the very next line, so you aren't leaking memory, but it's pointless and wasteful to create an object that you immediately discard. (Memory allocation is one of the slowest tasks in an OS like iOS. It has to make a kernel call)
If your program was using manual reference counting then you would have leaked the Catalogue object. It would never get deallocated. Those two lines should read like this:
Catalogue *catalog;
catalog = [arrayCheckout objectAtIndex:i];
Or even as 1 line:
Catalogue *catalog = [arrayCheckout objectAtIndex:i];

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