views:

63

answers:

4

I want to declare a c array as an instance variable (e.g. int arr[256]) in the interface block of a Cocoa object. I know that @property doesn't support c arrays but how to manually add the getter and setter for the c array and where should I alloc and release it?

Any input will be appreciated. I really don't want to use NSMutableArray for accessing int values.

A: 

You can declare them, but there is no such thing as a "setter" for a C array — you can't set them in C, only assign values to their indexes. You could have a getter and setter for a pointer, though that raises a whole host of memory management questions you'll have to answer.

Chuck
+1  A: 

where should I alloc and release it?

Well, you'll allocate and release it the same place you do for any instance variable: in init and dealloc. The trick is that you have to use malloc and free instead of retain and release.

As for the properties, you can declare them, you'll just have to write your own accessors and mutators.

Also, recall that, for this purpose, a C array is like a pointer.

With that said, you might do something like this:

@interface MyClass : NSObject
{
    int *arr;
}
@property int *arr;
@end

@implementation MyClass

#import <stdlib.h>

@dynamic arr;

- (id)init
{
    if ((self = [super init])) {
        arr = malloc(sizeof(int) * 256);
    }
    return self;
}

- (void)dealloc
{
    free(arr);
    [super dealloc];
}

- (int *)arr
{
    // Return a copy -- don't want the caller to deallocate
    // our instance variable, or alter it without our knowledge!
    // Also note that this will leak unless the caller releases it.
    int *arrCpy = malloc(sizeof(int) * 256);
    memcpy(arrCpy, arr, sizeof(int) * 256);
    return arrCpy;
}

- (void)setArr:(int *)anArr
{
    if (arr != anArr) {
        free(arr);
        // Again, copy the data so that the caller can't
        // change the values of specific ints without
        // out knowledge.
        int *anArrCpy = malloc(sizeof(int) * 256);
        memcpy(anArrCpy, anArr, sizeof(int) * 256);
        arr = anArrCpy;
    }
}

There's some better error checking you could do, and the code could be prettied up a bit, but that's the gist.

You could also use CoreFoundation data types, which are basically just C primitives and structs; memory management would be a bit easier, but it's also not the "straight C" ints that you requested.

To be honest, though, I think you'd be better off just using an NSArray of NSNumber objects -- memory management would be far easier, and it'd probably be more compatible with other Objective-C frameworks. It would also be more platform independent, since Cocoa takes into account 64-bit vs. 32-bit environments, as well as endianness, with its data types. At the very least, you should probably use NSInteger instead of int.

mipadi
You should change the method name of `arr`. Since it returns something that the caller is responsible for freeing, it should be called `copyArr` or something similar.
dreamlax
True; Jinru wanted an example of a property, though, so I wanted to show that.
mipadi
Thank both of you guys for such detailed answers. I really appreciate it. @mipadi: I'm doing some basic signal processing stuff (eg fft) on the iPhone, do you think I should use NSInteger or int for data arrays in terms of performance?
Jinru
Why are you using `@dynamic` there? You then implement the accessors yourself. `@dynamic` means they are implemented elsewhere (typically by a superclass, as in subclasses of NSManagedObject).
Peter Hosey
@Jinru: NSInteger is a typedef for the platform-specific "integer" data type. Not sure what it is on the iPhone, but it's probably an int anyway.
mipadi
A: 

If you just want an array of ints, and don't need to manage, or alloc and release it separate from the object itself, then just declare:

int arr[256];

in your @interface declarations, and your object will have an instance variable with room for 256 ints. If you want getters or setters for the int elements of the array, you will have to declare and write them manually (the old fashioned way before properties).

- (int)myElementOfArrAtIndex:(int)index {
  if (index >= 0 && index <= 255) {
    return (arr[index]);
  } else {
    // error handler
  }
}

etc.

There's no need to declare a pointer unless you want to manage memory of the array separate from the object (e.g. keep the array and release the object, or vice versa.)

hotpaw2
A: 

You can use structs to wrap up an array. This is probably the one exception that allows arrays to be copied by assignment. The benefit of this approach is that there is no need to explicitly allocate or free memory.

typedef struct
{
    int data[256];
} MyInts;


@interface MyClass : NSObject
{
    MyInts ints;
}
- (MyInts) ints;
- (void) setInts:(MyInts) someInts;
@end



@implementation MyClass

- (MyInts) ints
{
    return ints;
}

- (void) setInts:(MyInts) someInts
{
    ints = someInts;
}

@end


int main(void)
{
    MyInts ints = {{0}};
    ints.data[4] = 345;
    ints.data[5] = 123;
    ints.data[6] = 101;

    MyClass *someObj = [[MyClass alloc] init];

    [someObj setInts:ints]; // provide the ints to the object
    [someObj mutateTheInts]; // have object do something with them
    ints = [someObj ints]; // get them back

    return 0;
}
dreamlax