getting the values from Objects in NSMutableArray (console) - objective-c

As newbie, Im stuck on getting the values from objects I have put in a NSMutableArray. To give a full picture of my problem I would appreciate you reading the following:
(writing to console in Xcode)
Lets say I produce a new object as follows:
Person *player = [[Person alloc] init];
player.age = 10;
player.height = 10;
player.name = #"player";
As I continue to write my programme I can change the above values of player i.e
player.age = 23; etc.....
If I want to create another Person (player2) I repeat the above like this:
Person *player1 = [[Person alloc] init];
player1.age = 13;
player1.height = 4;
player1.name = #"player1";
In my programme I can now change and compare values of the 2 objects i.e.
if (player.age == player1.age) bla bla bla
My problem starts if I want to create 20+ Person objects - I know how to place all the objects in a loop/NSMutableArray as follows:
for (int i = 0; i < 20; i++)
{
Person *player = [[Person alloc] init];
player.age = 10;
player.height = 10;
player.name = #"player";
[myArray addObject:player];
[player release];
}
All the objects in myArray are individual but have the same values. Thats fine ! But how to get or change the objects in myArray ? (not at run time)
If [myArray objectAtIndex:4]; holds the following values:
player.age = 10;
player.height = 10;
player.name = #"player";
how do I get to the object(s) in myArray so I can compare/sort/add etc..
Heres example of what I want to do but I know is wrong:
if (player.age == [myArray personAtIndex:15.age];
or
NSLog(#"# has a height of %i",[myArray personAtIndex:15:name:height];
prints out>> person has a height of 10
I really would appreciate you helping me on this - As a newbie I'm finding it hard to move on until I get an understanding of this problem. Thank you very much for reading this.

You need to study the documentation for NSArray, in particular the objectAtIndex method.
[[(Person*)myArray objectAtIndex:15] age]
Will give you the value you want. I'll break this down:
(Person*) tells the compiler that you expect to get a Person object back
objectAtIndex returns an object (any object, hence the cast to Person above which prevents the compiler complaining that it might not respond to age) at index 15 of myArray
age has to be called on the returned object because you can't use dot notation on cast objects
Alternatively, you could do:
Person *aPerson = (Person*)[myArray objectAtIndex:15];
aPerson.age = 15;
Once you have an object of known type you can use dot syntax.

Related

Individual objects from Array are showing on NSLog with NSString but when addObject: to NSMutableArray, Array is null?

THIS IS WHERE THE PROBLEM LIES
NSString *individualEventTitle;
NSMutableArray *eventTitleArray = [[NSMutableArray alloc]init];
for (NSUInteger index =0; (index < 8) ; index++){
EventsList *eventList = [[EventsList alloc] initWithIndex:index];
NSString *individualEventTitle = eventList.eventTitle;
/*self.eventTitleArray = eventList.eventTitle;
self.eventLocationArray = eventList.eventLocation;
self.eventIconArray = eventList.eventIcon;
self.eventPriceArray = eventList.eventPrice;
self.eventTypeArray = eventList.eventType;*/
[eventTitleArray addObject:individualEventTitle];
NSLog(#"Title of Event:%#", individualEventTitle);
NSLog(#"Array of Event:%#", eventTitleArray);
}
So from my understanding, the loop should go through itself 8 times (to account for the number of items in my class array). To confirm this I NSLogged a string for the eventList.eventTitle and assigned it to a string called individualEventTitle. Upon reading the console I received ALL 8 event Titles.
However, when I add the command at the end of the loop, to add that string to the NSMutableArray *eventTitleArray. It appears null in the console when NSlogged.
I would highly appreciate some help, as I've spend the last two nights just tinkering with it with no avail!
Thank you!
Contents of my console
Console
Try to replace this line
[eventTitleArray addObject:[NSString stringWithFormat:#"%#",individualEventTitle]];

Objective-C Accessing Superclass Methods when Object Might be Superclass or Subclass

I'm an Objective-C noob working through a tutorial and I'm hitting a strange snag I want to understand better.
I'm looping to make a portfolio of stock objects that have a 50/50 chance of being a "foreignStock" or just being "stock" - the difference being a conversion rate property. The object stock is a superclass, with foreignStock being a subclass of stock.
I want to create a pointer, flip a coin to decide which type it is, and then assign the values I need. Since both the subclass and superclass have things like currentSharePrice, why can't I set them after the coin toss?
This is my main.m for review:
int main(int argc, const char * argv[]) {
#autoreleasepool {
// Declare portfolio and set the conversion rate
BNRPortfolio *mikesPortfolio = [[BNRPortfolio alloc] init];
NSUInteger globalConRate = 1.2;
// Array of ticker names - remove them as they are used
NSMutableArray *tickerNames = [[NSMutableArray alloc] init];
[tickerNames addObject:#"ibm"];
[tickerNames addObject:#"ppg"];
[tickerNames addObject:#"google"];
[tickerNames addObject:#"vrzn"];
[tickerNames addObject:#"apple"];
[tickerNames addObject:#"barq"];
// Create and add the stocks to the portfolio
for (int i = 0; i < 6; i++) {
id newStock;
// Coin flip to determine type
NSUInteger randomType = random() % 2;
if (randomType == 0) {
newStock = [[BNRStockHolding alloc] init];
} else {
newStock = [[BNRForeignStockHolding alloc] init];
newStock.conversionRate = globalConRate;
}
// Assign remaining values
newStock.purchaseSharePrice = 15 * (random() % i);
newStock.currentSharePrice = newStock.purchaseSharePrice * 1.4;
NSUInteger randomTickerValue = random() % [tickerNames count];
newStock.symbol = tickerNames[randomTickerValue];
[tickerNames removeObjectAtIndex:randomTickerValue];
[mikesPortfolio addHoldings:newStock];
}
}
The line inside the else{} block newStock.conversionRate... gives an Xcode pre-compile error stating "property not found for object of type __strong id" - I guess because it can't tell if newStock will actually be what I just declared it to be? But the assign statements at the end of main.m are showing the same line error as though newStock doesn't have those properties, even though BOTH classes will have access to them.
How do I make newStock understand that it will definitely be a class that has those properties but might ALSO have that conversion rate associated with the subclass?
I tried this:
BNRStockHolding newStock; <-- starting with superclass
// Coin flip to determine type
NSUInteger randomType = random() % 2;
if (randomType == 0) {
newStock = [[BNRStockHolding alloc] init];
} else {
newStock = [[BNRForeignStockHolding alloc] init];
newStock.conversionRate = globalConRate;
}
Which will make the errors on the bottom lines go away but still won't compile at the subclass method in the else{} block.
Where did I go wrong?
(I'm going to assume this is actually main.m, not main.c.)
Your primary mistake is using id rather than types.
id newStock;
This says that newStock is "some kind of object, I have no idea what." In ObjC, id can be sent any message, but it does not have any properties. So you can't use dot-notation on it. There are ways around that (don't use dot notation), but the better solution is to use a type:
BNRStockHolding *newStock = nil;
That will cause a problem here:
newStock = [[BNRForeignStockHolding alloc] init];
newStock.conversionRate = globalConRate;
Which you can fix this way:
BNRForeignStockHolding *foreignStock = [[BNRForeignStockHolding alloc] init];
foreignStock.conversionRate = globalConRate;
newStock = foreignStock;
But if the only thing that makes a foreign stock "foreign" is that it has a conversion rate, I would strongly recommend against subclassing here. Just make all stocks have a conversion rate. If it's domestic, make the conversion rate 1.

Declaring a pointer in a loop

everyone. My "engrish" is not very good but I hope you will understand my problem.
Let's say I have a code like this
-(id) init
{
if ( self = [super init] )
{
deck = [[NSMutableArray alloc] initWithCapacity:52];
Card *newCard = [[Card alloc] init];
for ( int suit = 0; suit < 4; suit++ )
for ( int rank = 0; rank < 13; rank++ )
{
newCard.suit = suit;
newCard.rank = rank;
[deck addObject:newCard];
}
[newCard release];
}
return self;
}
I'm feeling like I have a mistake in the aforementioned code. I want to create 52 different objects in nested loops and add every object in array. But I suspect that I'll have 52 same objects and in array will be 52 pointers that point to the same address, right?
What happens if I make like this.
-(id) init
{
if ( self = [super init] )
{
deck = [[NSMutableArray alloc] initWithCapacity:52];
for ( int suit = 0; suit < 4; suit++ )
for ( int rank = 0; rank < 13; rank++ )
{
Card *newCard = [[Card alloc] init]; // I guess every time newCard
newCard.suit = suit; // created, it will point to
newCard.rank = rank; // another chunk of memory,
[deck addObject:newCard]; // right?
[newCard release] // Should I release newCard every time?
}
}
return self;
}
So which way I can create 52 different cards?
Thank you. If you need more explanations, ask me.
First question: Your second code sniplet produces 52 individual objects which you add to the array.
The first sniplet, as you already suggested yourself, produces just one object which you add to the array. As it is one object only all the members of the array will carry the same values for .suit and .rank.
Als suggested already, when you nslog the objects then you see at least their address in memory. When the address is identical then it is the identical object.
Second question:
Yes, you should release it unless you use ARC. addObject will automatically retain each added object and release it upon removal from the array. So be careful when you fetch the object from the array later and intend to use it further. Then you may have to retain it again.
Alternative to your -correct- code you can autorelease the object using:
Card *newCard = [[[Card alloc] init] autorelease]; // I guess every time newCard
newCard.suit = suit; // created, it will point to
newCard.rank = rank; // another chunk of memory,
[deck addObject:newCard]; // right?
//[newCard release]; // not required, autoreleased
(However, a semicolon is missing following the release statement. )

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

Creating 20 objects in a loop

I need some newbie help.
So basically im trying create 20 individual objects (players). Each player has a name , age and height.
Instead of writing 'Person *player = [[Person alloc] init];' Twenty times, I have made a loop.
I think the loop has worked because the [myArray count] has 20 objects.
My questions:
Are the 20 objects unique ( all with same name, age, height) ?
Whats the best way to give each object in each element of MyArray a name,age,height ?
So my end goal is to be able to do something like this:
NSLog(#"%# is %i high and is %i years old", player1.name, player1.height, player1.age);
NSLog(#"%# is %i high and is %i years old", player2.name, player2.height, player2.age);
etc...
I hope the above makes sense and I really appreciate your help.
#import <Foundation/Foundation.h>
#import "Person.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *myArray = [[NSMutableArray alloc]initWithCapacity:20];
for (int i = 0; i < 20; i++)
{
Person *player = [[Person alloc] init];
player.age = 10;
player.height = 10;
player.name = #"player";
[myArray addObject:player];
[player release];
}
NSLog(#"The number of players in myArray = %i", [myArray count]); // I now have 20 players (objects) in myArray.
//How can I now give each player object an individual name, age & height ??
[pool drain];
return 0;
}
Are the objects unique? YES, they are.
What the best way to give each object a name,age,height? this question is not clear, so the way you gave an age, height and name to your objects in the loop is correct but of course you're providing the same info to all objects; giving them unique names depends on your application logic, for example you could assign the age randomly in this way:
player.age = arc4random()%90;
You can do the same for the height (eventually with a slightly more complicated formula, e.g. 140+arc4random()%50). Finally for the height you can assign a derived name in this way:
player.name = [NSString stringWithFormat:#"Player-%d",i];
which assigns names Player-0, Player-1, ...
Finally to print-out the data in the NSLog:
NSLog(#"Player %d : name=%# height=%d age=%d",i,player.name,player.height,player.d)
or in a different loop:
int i = 0;
for(Person *player in myArray) {
NSLog(#"Player %d : name=%# height=%d age=%d",i,player.name,player.height,player.d);
i++;
}
A couple of items.
If I understand your follow up question properly, what you are looking to do is access the objects you have stored in your array so that you can change the values of their properties.
However, the above poster answered the actual question you asked, and you should mark his correct.
If you wanted to go through each item in the array you would do the following:
for (int i=0; i<[players count]; i++) {
Player *aPlayer = [players objectAtIndex:i];
aPlayer.name = #"joe";
}
If you only wanted to access a single player:
Player *aPlayer = [players objectAtIndex:4];
aPlayer.name = #"joe";
Also you may want to customize your Player class and override the description so that you don't have to repeatedly type complex NSLog statements.
-(NSString *)description{
return [NSString stringWithFormat:#"name = %# age = %d height = %d", self.name, self.age, self.height];
}
By overriding the description method calling NSLog on your object will return the string from this statement.