Creating 20 objects in a loop - objective-c

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.

Related

Objective C: Memory Management, releasing an object with multiple references

I would like to release a Car object present in the dealer. I would like to know what is the right way of doing it. NSMutableArray Inventory stores the cars for a particular dealer. So, now I would like to present the user with a delete functionality, so, user could select the car using the Vin Number and delete it. But if I try to find the car and release the reference that doesn't works. Would I need to remove the object from the Array and then, release the reference? I am fairly new to objective c and in the initial learning phase. Thank you.
#import "Dealer.h"
#import "Address.h"
#import "PhoneNumber.h"
#implementation Dealer
static NSInteger dealerIdAllocater = 0;
-(id) init{
self = [super init];
self.dealerId = ++dealerIdAllocater;
self.addressList = [[NSMutableArray alloc] init];
self.inventory = [[NSMutableArray alloc] init];
return self;
}
#synthesize dealerId, name, addressList, inventory;
-(void)addCarInInventory:(Car*)car{
[self.inventory addObject: car];
}
-(void)displayAddresses{
for(Address *address in self.addressList){
NSLog(#"Street Address: %#", address.streetAddress);
NSLog(#"City: %#", address.city);
NSLog(#"State: %#", address.state);
NSLog(#"Country: %#", address.country);
for(int i=0; i<[address.phoneNumber count]; i++){
PhoneNumber *phoneNumber = [address.phoneNumber objectAtIndex:i];
NSLog(#"Phone Number %i, %#", i, phoneNumber.phoneNumber);
}
NSLog(#"--------------");
}
}
-(void)displayInventory{
for(Car *car in self.inventory){
[car displayInformation];
}
NSLog(#"--------------");
}
-(Car *)findCarById:(NSString *)vinNumber{
for(Car *car in self.inventory){
if ([vinNumber isEqualToString:car.vinNumber]) {
return car;
}
}
return nil;
}
#end
Would I need to remove the object from the Array and then, release the reference?
Yes, containers such as NSMutableArrays increment the retain count of objects by 1 when added to them. This is to make sure the container will always hold a valid reference to an object. When you remove an object from the container, the retain count will be decremented by 1.

Objective-C variable dynamic naming/referencing at runtime

I have a variable name referencing question for the Objective C gurus out there.
Lets say I have 6 UILabels on a form, the are setup with properties naming them myLabel1 - myLabel6
I would like to go through a for loop and populate these with something depending on the loop but im unsure how to specifiy the for loops variable and make it part of the labels name.
Here is what I would like to do:
for (int LP = 0; i <5)
{
labelLP.text = [NSString stringWithFormat:#"My label number:%d", LP};
}
What im not sure of is how to reference the label and append the LP int and use it in my loop. I'm sure there is a way to do this just not sure how.. Anyone??
you can always take advantage of the dynamic runtime of objective-c:
id var = object_getIvar(self,class_getInstanceVariable([self class], [[NSString stringWithFormat:#"label%d",LP] UTF8String]));
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
Whether one likes this approach is a question of style, but here's a way that should work:
for (int LP = 1; i <=6)
{
NSString *labelName = [NSString stringWithFormat: #"label%d", i];
UILabel *labelLP = (UILabel*)[self valueForKey: labelName];
labelLP.text = [NSString stringWithFormat:#"My label number:%d", LP};
}
I don't think you can create variable names on the fly, at least not trivially.
You could always use a switch case inside your loop:
for (int i=0; i<5; i++) {
switch(i) {
case 1:
myLabel1.text = [NSString stringWithFormat:#"My label number: %d", i];
break;
case 2:
myLabel2.text = [NSString stringWithFormat:#"My label number: %d", i];
break;
...
...
}
}
You could also store your labels in an array, and loop through that array.
The important point is not to get fixated about the variable names, but to think about why you need your objects and how to get them.

Problems sending messages to NSMutableArrays within C-Arrays

I'm currently trying to implement a pooling system, I have all the code, I just dont understand why a certain part of it doesn't work.
I have a c-array of NSMutable array made like this:
NSMutableArray *poolArray[xSize][ySize];
for (int n = 0; n < xSize; n++)
{
for (int m = 0; m < ySize; m++)
{
poolArray[n][m] = [[NSMutableArray alloc] init];
}
}
And whilst trying to access it I get the x and y coordinate of the pool and object is in and try to add it like this:
[poolArray[x][y] addObject:object]; //This raises a EXC_BAD_ACCESS error
I am totally open to editing how I write this - I am aware that I could declare a NSMutableArray and use indexes of ((y * width) + x) and I may have to rewite the code like that. But preferably I dont want to have to do that as I only want to actually create the arrays I'm using so something like this:
if (poolArray[x][y] == nil) poolArray[x][y] = [[NSMutableArray alloc] init];
[poolArray[x][y] addObject:object];
This is so that it can have 'holes' so I dont have to make anything at poolArray[2][3] for example if there is nothing there.
I don't know if there is anyway that I could rewrite that with objective-c types, but if I do I'm forced to keep creating a NSMutableArray at every space, the reason I dont want to do that is because I want to get every little bit of performance I can out of the system.
Thanks for taking the time to read this, and any response is appreciated :)
This works for me:
#import <Foundation/Foundation.h>
#define xSize 10
#define ySize 10
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *poolArray[xSize][ySize];
for (int n = 0; n < xSize; n++)
{
for (int m = 0; m < ySize; m++)
{
poolArray[n][m] = [[NSMutableArray alloc] init];
}
}
[poolArray[2][3] addObject: #"Hello"];
[poolArray[2][3] addObject: #"world!"];
NSLog(#"poolArray[2][3] objects: %# %#",
[poolArray[2][3] objectAtIndex: 0],
[poolArray[2][3] objectAtIndex: 1]);
[pool drain];
return 0;
}
(Yes, I know, I should release all NSMutableArray instances. Left out for brevity).
So there are a few things you should check:
Is object a valid object, i.e. was it initialized? The NSMutableArray will try to retain the object, and if it was never initialized, that will fail miserably, or if it was dealloc-ed already, it will fail too.
are x and y valid? You can easily go over the boundaries and not notice it.
Can't see anything wrong with the code you've provided, although a couple of ideas:
In the case where your checking poolArray[x][y] == nil have you actually reset all the values to nil when you initialize the array?
An alternative that should work, is to store the array on the heap. You could use calloc (which will initialize the memory to 0), or malloc and memset.
The following should work:
NSMutableArray ***poolArray = calloc(xSize * ySize, sizeof(NSMutableArray *));
if (poolArray[x][y] == nil) poolArray[x][y] = [[NSMutableArray alloc] init];
[poolArray[x][y] addObject:object];

getting the values from Objects in NSMutableArray (console)

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.

How do I init a NSArray with a set of images that reocur?

EDIT: I think i asked something really wrong over here, and i am sorry. What i am doing, is a mock of a slot machine, but i don't think that it will be wise(just don't want to insult myself) of me to put 250(50*5) images in the UIPICKERVIEW, There is no reason doing that, My idea now is to use only the 6 images for each column in deferent order and then when i spin just go again and again over the 30(6*5) images and spin them, that will give the same effect while using less resources, right? I can't see what i was thinking, and thank you all for the answers
Implementing a complex UIPickerView (5 components) in iOS, I am stuck on this problem...
I have 5 NSArrays (for each component in the picker...not mutable) and I have 6 images.
I need to init every array with the set of images, that will populate the array for 50 images, set after set (I'm guessing some kind of for loop that will run 8 times and populate the array with 2 more images at the end?)
In every array the images need to be in a different order, but again, for the same array the set has to be the same all the way.
When I say a set I mean that I need to put the images in the same order again and again, not that they are in another array or anything like that....
Can any one help with this?
10x,
Erez
Not sure I understood the question, but, if I did, you may do:
NSArray *set = [NSArray arrayWithObjects:[UIImage imageNamed:#"img1.png"],/* all the images */ , nil];
NSMutableArray *tmp = [[NSMutableArray alloc] init];
for (int i = 0; i<50; i++) {
[tmp addObject:[set objectAtIndex:(i%6)]];
}
then you may use tmp as common NSArray, or do something like
NSArray *result = [NSArray arrayWithArray:tmp];
ps. don't forget to release tmp when you finished.
UIImage *image;
int randomIndex;
NSCountedSet *set = [[NSCountedSet alloc] initWithCapacity:50];
NSMutableArray *arrays = [[NSMutableArray alloc] initWithCapacity:5];
for ( int i = 0; i < 5; i++ ) {
while ( [set count] < 50 ) {
randomIndex = arc4random() % 6;
image = [images objectAtIndex:randomIndex];
switch ( [set count] ) {
case 48:
case 49:
if ( [set countForObject:image] < 9 ) {
[set addObject:image];
}
break;
default:
if ( [set countForObject:image] < 8 ) {
[set addObject:image];
}
}
}
[arrays addObject:[set allObjects]];
[set removeAllObjects];
}
[set release];
The idea would be to use a counted set and get the count of elements added to it. This way we can keep track of objects being added.