willc2
willc2

Reputation: 39671

In Objective-C, can I declare @property on a c-array of floats?

thing.h

@interface Thing : NSObject 
{
     float stuff[30];
}

@property float stuff;
@end

thing.m

@implementation Thing
@synthesize stuff;
@end

I get error: type of property 'stuff' does not match type of ivar 'stuff'

I don't want to use an NSArray because I'd have to make the floats into NSNumbers (right?) and that's a pain to do math with.

Update: I've noticed similar answers had guesses and trial answers. While I appreciate the attempts by non-Objective-C folks, I'm hoping for a definitive answer whether it's possible or not.

Upvotes: 2

Views: 8421

Answers (6)

Qubei
Qubei

Reputation: 1069

Daniel's FloatHolder answer has a major bug (edit: he's now fixed it). It only allocates memory for one float and not for the whole array.

The line:

_values = malloc(sizeof(float));

Should be:

_values = malloc(sizeof(float) * count);

Otherwise it seems to be a good answer. Sorry couldn't work out how to reply directly. (edit: I didn't have the necessary privilege on stackoverflow then.)

Upvotes: 2

Daniel
Daniel

Reputation: 4967

OK, I have compiled up the following code at it works as expected.

FloatHolder.h

@interface FloatHolder : NSObject {
    int _count;
    float* _values;
}

- (id) initWithCount:(int)count;

// possibly look into this for making access shorter
// http://vgable.com/blog/2009/05/15/concise-nsdictionary-and-nsarray-lookup/
- (float)getValueAtIndex:(int)index;
- (void)setValue:(float)value atIndex:(int)index;

@property(readonly) int count;
@property(readonly) float* values; // allows direct unsafe access to the values

@end

FloatHolder.m

#import "FloatHolder.h"


@implementation FloatHolder

@synthesize count = _count;
@synthesize values = _values;

- (id) initWithCount:(int)count {
    self = [super init];
    if (self != nil) {
        _count = count;
        _values = malloc(sizeof(float)*count);
    }
    return self;
}

- (void) dealloc
{
    free(_values);

    [super dealloc];
}

- (float)getValueAtIndex:(int)index {
    if(index<0 || index>=_count) {
        @throw [NSException exceptionWithName: @"Exception" reason: @"Index out of bounds" userInfo: nil];
    }

    return _values[index];
}

- (void)setValue:(float)value atIndex:(int)index {
    if(index<0 || index>=_count) {
        @throw [NSException exceptionWithName: @"Exception" reason: @"Index out of bounds" userInfo: nil];
    }

    _values[index] = value;
}

@end

then in your other application code you can do something like the following:

** FloatTestCode.h **

#import <Cocoa/Cocoa.h>
#import "FloatHolder.h"

@interface FloatTestCode : NSObject {
    FloatHolder* holder;
}

- (void) doIt:(id)sender;

@end

** FloatTestCode.m **

#import "FloatTestCode.h"


@implementation FloatTestCode

- (id) init
{
    self = [super init];
    if (self != nil) {
        holder = [[[FloatHolder alloc] initWithCount: 10] retain];
    }
    return self;
}

- (void) dealloc
{
    [holder release];

    [super dealloc];
}

- (void) doIt:(id)sender {
    holder.values[1] = 10;
}

Upvotes: 8

Adam Rosenfield
Adam Rosenfield

Reputation: 400264

You can't do it the way you want to do it. You can jump through some hoops and get something similar, e.g. using Daniel's solution, but it's not quite the same thing. The reason you can't do it is that arrays are not lvalues in C. An lvalue is something that can appear on the left-hand side of an assignment. The following code is invalid C:

float stuff1[30], stuff2[30];
stuff1 = stuff2;  // ERROR: arrays are not lvalues

As a consequence, you can't declare properties whose types are not lvalues.

Upvotes: 2

smorgan
smorgan

Reputation: 21579

Even if you could get that to compile, it wouldn't behave well. 'stuff' would return a float*, and the client would have no idea how long the array way; 'setStuff:' would just change the pointer, and you'd either be pointing to stack-allocated data that would vanish out from under you or heap-allocated data that would leak because it wouldn't know to free it.

Upvotes: 1

Daniel
Daniel

Reputation: 4967

The type of the property must match the type of the instance variable it will be stored in, so you could do something like

  @interface Thing : NSObject 
  {
       float stuff[30];
  }

  @property float[30] stuff;
  @end

and it should work. I wouldn't recommend it though. I'm guessing you're looking for something like indexed properties from Delphi. The closest you'll get is something like the following.

  @interface Thing : NSObject 
  {
       float stuff[30];
  }

  - (void) setStuff:(float)value atIndex:(int)index;
  - (float) getStuffAtIndex:(int)index;
  @end

Upvotes: 6

mipadi
mipadi

Reputation: 410652

I'm not well-versed in Objective-C 2.0, but I'm guessing that the issue might be caused by the fact that a C array is essentially just a pointer to the first element of the array, meaning that the type of float stuff[30] is actually float *, not merely a float.

Upvotes: 0

Related Questions