declaring double arrays in objective-c - objective-c

My map object has a set of coordinates. It doesn't always have the same number of coordinates.
In java I'd just declare the object as Double[] xpoints and would set it's size when instantiating a map like this: xpoints = new double[npoints];
How can I do this with objective-c?
I tried doing this: #property(nonatomic) double * xpoints; but somehow all of it's values turn to 0 when I print it with NSLog.
Map's init:
-(id)initWithXpoints:(double[]) xpointss Ypoints:(double[]) ypointss Npoints:(int)npointss
{
self = [super init];
if (self)
{
self.xpoints = xpointss;
self.ypoints = ypointss;
self.npoints = npointss;
}
return self;
}
Something weird happens though. The values are changed to zero when I print xpoints[0] from the object that created the map. The first time I print it it works. The second time it just prints zero.
I think it happens because xpointss sent to init is removed from the memory. How can I "instantiate" the xpoints property if it's a pointer?
Is there a better way to do this?
added: I tried creating a temporary xpoints like this:
double tempxpoints[npointss];
double tempypoints[npointss];
for (int i = 0; i < npointss; i++)
{
tempxpoints[i] = xpointss[i];
tempypoints[i] = ypointss[i];
}
self.xpoints = tempxpoints;
self.ypoints = tempypoints;
But it still didn't work.
Edit: Thanks for all the answers. This ended up being my final Init code:
-(id)initWithXpoints:(double[]) xpointss Ypoints:(double[]) ypointss Npoints:(int)npointss
{
self = [super init];
if (self)
{
_xpoints = [[NSMutableArray alloc] init];
_ypoints = [[NSMutableArray alloc] init];
for (int i = 0; i < npointss; i++)
{
NSNumber *tempx = [NSNumber numberWithDouble:xpointss[i]];
NSNumber *tempy = [NSNumber numberWithDouble:ypointss[i]];
[_xpoints addObject:tempx];
[_ypoints addObject:tempy];
}
_npoints = npointss;
}
return self;
}

If you allocate the arrays as local variables, then they will be allocated on the stack. When execution leaves the function, those memory areas are freed up. You must use malloc() to allocate arrays that you can pass around and use free() to free them up.
// to allocate
double[] tempxpoints = (double[])malloc(sizeof(double) * npointss);
// to free when not used any more
free(tempxpoints);
But actually NSArray has been designed to handle these cases. And with ARC you don't even have to care about freeing the memory.
NSMutableArray *tempxpoints = [[NSMutableArray alloc] init];
[tempxpoints addObject:#2]; // wrap the double in an NSNumber object

If you were being fully Objective-C about it, you'd use an NSArray, fill it with NSNumbers and never specify a length. You can usually give them hints about how much space is likely to be required but Objective-C's collections all always size dynamically.
As of recent versions of the compiler, you can use array[x] notation on NSArray and write direct NSNumber constants as e.g. #4.5f if that sweetens the deal at all.
If you literally want C-style arrays then you'll need to descend to the C level of thought. So, something like:
#property(nonatomic, readonly) double * xpoints;
And:
-(id)initWithXpoints:(double[]) xpointss Ypoints:(double[]) ypointss Npoints:(int)npointss
{
self = [super init];
if (self){
size_t sizeOfArraysInBytes = sizeof(double)*npointss;
_xpoints = (double *)malloc(sizeOfArraysInBytes);
memcpy(_xpoints, xpointss, sizeOfArraysInBytes);
/* ... etc ... */
/* you never use self. notation in an init because it's a method call,
and method calls on objects that are not yet fully instantiated aren't
safe. Sample cause of failure: a subclass overrides the setter */
}
return self;
}
- (void)dealloc
{
free(_xpoints);
/* ... etc ... */
}
The array itself will be read/write elsewhere (it's the pointer that's read-only, not the things it points to) as class.xpoints[0], etc.

Related

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. )

Storing objects in an array in objective c

I'm trying to store 25 objects in an array
for (int iy=0; iy<5; iy++) {
for (int ix=0; ix<5; ix++) {
TerrainHex *myObject = [[TerrainHex alloc] initWithName:(#"grassHex instance 10000") width:mGameWidth height:mGameHeight indexX:ix indexY:iy];
myObject.myImage.y += 100;
[TerrainHexArray addObject:myObject];
[self addChild:(id)myObject.myImage];
}
}
NSLog(#"Terrain array: %u", [TerrainHexArray count]);
The log is coming back as zero though.
In the .h file I have
#property NSMutableArray *TerrainHexArray;
And in the .m file I have..
#synthesize TerrainHexArray;
I just tried what someone suggested below, which is..
NSMutableArray *TerrainHexArray = [[NSMutableArray] alloc] init];
But it's just giving me a warning saying expected identifier.
It's almost certain that TerrainHexArray does not exist when you're doing the addObject calls and the NSLog. You say you tried adding the alloc/init after someone suggested it, which indicates you don't understand object management in Objective-C.
I'd suggest you step back, find a book on Objective-C, and read at least the first few chapters (up through the discussion of alloc/init et al) before you attempt any more coding.
Incidentally, it's standard C++/Objective-C coding practice (except in Microsoft) to use identifiers with a leading lower case character for instance names, reserving leading caps for types/class names.
What is TerrainHexArray? It looks like a class name, not an instance of an array. If you create a mutable array, then you can add the items to the array.
NSMutableArray *hexArray = [[NSMutableArray] alloc] init];
for (int iy=0; iy<5; iy++) {
for (int ix=0; ix<5; ix++) {
TerrainHex *myObject = [[TerrainHex alloc] initWithName:(#"grassHex instance 10000") width:mGameWidth height:mGameHeight indexX:ix indexY:iy];
myObject.myImage.y += 100;
[hexArray addObject:myObject];
[self addChild:(id)myObject.myImage];
}
}
NSLog(#"Terrain array: %u", [hexArray count]);

How to manage int when it's incremented inside another loop?

I have a simple loop with an int counter that gets incremented inside a while loop when a special case exists. My question is simply - how should I manage memory inside this function with regards to the int specifically? I've been using NSNumber almost exclusively and what little time I've spent with int seems to make me think I'm not doing releasing it correctly.
Any other improvements are also welcome but I'm very interested in the int question
- (NSArray *)parseJson:(NSArray *) items
{
NSMutableArray* hats = [[NSMutableArray alloc] init];
NSEnumerator *enumerator = [items objectEnumerator];
NSDictionary* item;
int counterz = 0;
while (item = (NSDictionary*)[enumerator nextObject]) {
Hat* hat = [[Hat alloc] init];
hat.addr = [item objectForKey:#"Address"];
BOOL* hasHat = [item objectForKey:#"HasHat"];
if ([hasHat boolValue]) {
if (counterz < 10) {
[hats addObject:hat];
counterz++;
}
}
}
return hats;
}
Thank you in advance!
You don't need to release a "normal" (i.e.: non-object based) int - it'll happily life out its (brief, tragic) life on the stack until it falls out of scope.
You've got a couple unnecessary things and some memory leaks...
- (NSArray *)parseJson:(NSArray *) items {
NSMutableArray *hats = [NSMutableArray array];
int counter = 0;
for (NSDictionary *item in items) {
Hat *hat = [[Hat alloc] init];
[hat setAddr:[item objectForKey:#"Address"]];
BOOL hasHat = [[item objectForKey:#"HasHat"] boolValue];
if (hasHat && counter < 10) {
[hats addObject:hat];
counter++;
}
[hat release];
}
return hats;
}
And heck, once you reach a counter of 10, you could break out of the loop, because you're never going to do anything useful once 10 is reached.
Some other comments:
The name of the method is wrong. Nothing about this method has to do with parsing JSON. At best you're interpreting an array of dictionaries that happened to originate from a JSON string, but there's nothing about the nature of this code that says "this is parsing JSON".
-[NSDictionary objectForKey:] returns an object. A BOOL is not an object, it's a primitive (like an int or char). Appending * to the type does not make it an object either. :)
Since the method name does not begin with new or alloc and does not contain the word copy, you're supposed to return an autoreleased object from it. The method in the question was returning an owned object (+1 retain count), since you invoked alloc, but never autorelease. Using the convenience constructor +array fixes this.
In your loop, you allocated a Hat object, but never released it. This is a classic memory leak.

How to change this so that it returns arrays

The following code works perfectly and shows the correct output:
- (void)viewDidLoad {
[super viewDidLoad];
[self expand_combinations:#"abcd" arg2:#"" arg3:3];
}
-(void) expand_combinations: (NSString *) remaining_string arg2:(NSString *)s arg3:(int) remain_depth
{
if(remain_depth==0)
{
printf("%s\n",[s UTF8String]);
return;
}
NSString *str = [[NSString alloc] initWithString:s];
for(int k=0; k < [remaining_string length]; ++k)
{
str = [s stringByAppendingString:[[remaining_string substringFromIndex:k] substringToIndex:1]];
[self expand_combinations:[remaining_string substringFromIndex:k+1] arg2:str arg3:remain_depth - 1];
}
return;
}
However, instead of outputting the results, I want to return them to an NSArray. How can this code be changed to do that? I need to use the information that this function generates in other parts of my program.
There are several things that you need to change in your code.
First - consider changing the name of your method to something more legible and meaningful than -expand_combinations:arg2:arg3.
Second - you have a memory leak. You don't need to set allocate memory and initialize str with the string s, because you change its value right away in the loop without releasing the old value.
Third - take a look at NSMutableArray. At the beginning of the method, create an array with [NSMutableArray array], and at every line that you have printf, instead, add the string to the array. Then return it.
basicaly you have:
create mutable array in viewDidLoad before [self expand_combinations ...
add aditional parameter (mutable array) to expand_combinations
populate array in expand_combinations

Declare Dynamic Array

How can I declare dynamic array? For example:
int k=5;
I want to have an array like below:
int myArray[k];
if i read the question right.. (unlikely at this point)
NSMutableArray *myArray = [[NSMutableArray alloc] initWithCapacity:k];
Sometimes true arrays (not NSArray) are really needed. See for example indexPathWithIndexes:length: in NSIndexPath, it take array of uintegers as parameter. For array allocation you should use the following approach:
NSUInteger *arr = (NSUInteger*)malloc(elementsCount * sizeof(NSUInteger) );
arr[0] = 100;
free(arr);
In Objective-C, the standard way to do this is to use the NSMutableArray class. This is a container that can hold any object (note that int is not an object! You'll have to wrap your integers in NSNumber.) Quick example:
NSMutableArray* someIntegers = [[NSMutableArray alloc] initWithCapacity:1];
[someIntegers addObject:[NSNumber numberWithInt:2]];
//I've added one thing to my array.
[someIntegers addObject:[NSNumber numberWithInt:4]];
//See how I can put more objects in than my capacity allows?
//The array will automatically expand if needed.
//The array now contains 2 (at index 0) and 4 (at index 1)
int secondInteger = [[someIntegers objectAtIndex:1] intValue];
//Retrieving an item. -intValue is needed because I stored it as NSNumber,
//which was necessary, because NSMutableArray holds objects, not primitives.
Well in my book it's ok to use VLAs in Objective-C.
So something like
int foo = 10;
int bar[foo];
is allowed. Of course this is not a dynamic array as in automatically adjusting its size. But if you only need a native array on the stack that's fine.
You can use Objetive-C++.
First rename your class like this: MyClass.mm the ".mm" extension tells Xcode that this clas is a Objetive-C++ class, not a Objetive-C class.
then you can use dynamics C++ arrays like this:
int *pixels = new int[self.view.size.width];
for (int offset = 0; offset = self.view.size.width; offset++) {
pixeles[offset] = rawData[offset];
}
then you can pass "pixels" in a method:
Scan *myScan = [[Scan alloc] initWhithArray:pixels];
the method "initWithScan" is declared like this:
-(id)initWithArray:int[]pixels;
the "initWithScan" implementation is like this:
-(id)initWithScan:int[]pixels {
if (self = [super init]) {
for (int i = 0; i < self.myView.size.width; i++) {
NSLog(#"Pixel: %i", pixels[i];
}
}
return self;
}
I hoppe this was useful.