views:

1761

answers:

7

Is this a valid way to initalize an NSArray with float objects?

NSArray *fatArray = [NSArray arrayWithObjects:
                    [NSNumber numberWithFloat:6.9],
                    [NSNumber numberWithFloat:4.7],
                    [NSNumber numberWithFloat:6.6],
                    [NSNumber numberWithFloat:6.9],nil];

It works and it feels right, just wanted to make sure I was on the right track.

gary

+4  A: 

As far as I know, this is a perfectly valid way of putting floats in an NSArray.

mouviciel
It *is* the way!
Wevah
+1  A: 

I agree with mouviciel. Since you can't put simple types into an Array this is the way to do it. Looks a bit strange and is a lot of code to write but it is fine.

Holli
+9  A: 

As mouviciel already wrote, this is the way to do it. When I write something like this I usually make the code shorter using a simple macro:

#define FBOX(x) [NSNumber numberWithFloat:x]

Then you can rewrite the code like this:

NSArray *fatArray = [NSArray arrayWithObjects:
    FBOX(6.9), FBOX(4.7), FBOX(6.6), FBOX(6.9), nil];

Macros are evil, but in this case the macro is so simple I’d use it. Plus the code hurts a bit less to read, especially if the macro definition is not far.

If you wrote a lot code like this, you could create a category with a custom initializer with variable number of float arguments, but then there’s a problem ending the argument list. You could pass the total number of floats first:

- (id) initWithFloats: (int) numFloats data: (float) float1, ...;

But counting the arguments by hand is prone to error. Or you could use some sentinel value such as zero that would mark the end of the argument list, but this opens a whole new can of worms called floating-point comparison.

zoul
thank you, much appreciated
fuzzygoat
Comparisons with 0.0 are not problematic, but that's often not a useful sentinel value. I like the macro idea, though.
Mark Bessey
+2  A: 

going off on a slight tangent, if all you want to do is store an array of floats and don't really need the added functionality of an NSArray or NSNumber, then you should also consider just a standard C array:

float fatArray[] = {6.6, 6.9, 4.7, 6.9};
pxl
Of course, C arrays aren't bounds-checked or reference-counted, so if you write a bug involving one, you're less likely to catch it quickly.
Peter Hosey
true, but it does seem a bit wasteful to allocate 5 objects to store 4 floats.
pxl
+1  A: 

If you're going to be creating a lot of these arrays with exactly the same number of elements, you could define a FloatArrayFactory class that implements something like:

+ (NSArray *) arrayWithFloat: (float)f;
+ (NSArray *) arrayWithFloat: (float)f1 and: (float)f2;
+ (NSArray *) arrayWithFloat: (float)f1 and: (float)f2 and: (float)f3;
+ (NSArray *) arrayWithFloat: (float)f1 and: (float)f2 and: (float)f3 and: (float)f4;

And if that's too verbose, you could go for the terse and funky look of unnamed parameters:

+ (NSArray *) arr: (float)f1 : (float)f2 : (float)f3;

which you can call like this:

NSArray *a = [Factory arr: 1.0 :2.0 :3.0 :4.0];
Mark Bessey
Or instead of a factory, make it a category (this is what they were invented for)
Dave DeLong
I actually wrote this as a category originally, but figured it wasn't all that useful to add construction methods to NSArray.
Mark Bessey
+1  A: 

If you have a lot of floats to convert, or want to paste them in from a comma separated list, it may be easier to call a function that converts floats into an NSArray instance.

NSArray*  arrayFromFloats(NSUInteger count, float *floats)
{
    NSMutableArray* ma = [NSMutableArray arrayWithCapacity:count]; 
    NSUInteger i; 
    for (i=0; i<count; i++) { 
     [ma addObject:[NSNumber numberWithFloat:floats[i]]];
    }
    return (NSArray*)ma; 
}

Example caller:

static float floats[] = {1.1, 2.2, 3.3}; 
NSUInteger count = sizeof(floats)/sizeof(float);
NSArray* a = arrayFromFloats(count, floats);
First off, since there's no reason to pass a negative `count`, it should be unsigned; `int`, not otherwise qualified, is signed. Second, it should be `NSUInteger` instead of (`unsigned`) `int`, just in case you ever have more than four billion `float`s (possible when running in 64-bit).
Peter Hosey
Thank you, Peter. I changed `int` to `NSUInteger` in my example code.
not agreeing on NSUInteger instead of unsigned int; unsigned int is ok, why not (and NSUInteger _can_ be `unsigned int`, and we don't need more to index ~4*10^9 elements which is enough for a lot of application)
ShinTakezou
A: 

Another lazy option is to just use an array of NSStrings and then getting the type of value you are looking for directly from the string.

Like so:

NSArray *arrayOfNumbers = [NSArray arrayWithObjects:@"3.12",@"3.2", @"12", @"15", nil];
float number = [[arrayOfNumbers objectAtIndex:0] floatValue];
isaac