How should I write a property declaration for C array in ObjC? - objective-c

I currently have this code:
#interface Matrix4 : NSObject
{
float mat[16];
}
#property (readonly) float mat[1];
I want the property to either give me the mat array or have multiple properties giving me readonly access to mat[1], mat[2], etc.
I current have "Property cannot have array of function type float[1]" as an error message

Arrays cannot be return values, so the property cannot have an array type. Instead you must return a pointer, so declare the property as a pointer to the element type of the array:
#property (readonly) float *mat;
Keep the instance variable as float mat[16] as you have now. Then implement the accessor to return a pointer to the array:
- (float *)mat {
return mat; // array decays to pointer automatically
}
Alternatively, you could have an accessor directly for the individual elements:
- (float)matIndex:(NSUInteger)i {
// maybe check bounds here?
return mat[i];
}
The problem with these approaches is that the information about the size of the array is lost, so you would probably want to put the size of the array in a macro or const variable. If you need something a bit more object-oriented, make the array an NSArray and store NSNumbers in it.
edit: One option would also be to wrap the array in a struct to preserve the size info, though you still probably want to pass it around by reference:
struct matrixf16 {
float f[16];
};
#interface Matrix4 : NSObject {
struct matrixf16 mat;
}
#property (readonly) struct matrixf16 *mat;
(Also, if I'm guessing correctly that the size is 16 because it's meant to hold a 4×4 matrix, why not make the array float f[4][4].)

As the compiler is telling you, properties cannot have array or function type.
You can manually implement the getter, like
#interface Matrix4 : NSObject {
float mat[16];
}
- (float *)mat;
#implementation
- (float *)mat {
return mat;
}
or you can consider using an NSArray instead, depending on your requirements. NSArray is definitely more overweight than a native C array, but it allows you to use properties.
However I suspect you have a design issue: it looks like you are trying to implement a squared matrix, but you are exposing the internal representation, most likely so that the client can set the matrix elements.
You should instead hide the internal representation and only expose methods to perform matrix operations. For instance, you can think of exposing a method which sets the matrix value, as:
- (void)setValue:(float)value forRow:(int)row column:(int)col {
NSParameterAssert(row >= 0 && row < 4 && col >= 0 && col < 4)
mat[row * 4 + col] = value;
}
and one that gives you an element back
- (float)valueForRow:(int)row column:(int)col {
NSParameterAssert(row >= 0 && row < 4 && col >= 0 && col < 4)
return mat[row * 4 + col];
}
and make the mat ivar private. This gives you also the flexibility of changing the internal representation at will, without breaking the client's code.
The above implementation is also very easy to generalize to a squared matrix of size, by providing a dimension parameter and using a NSArray or dynamic memory allocation (since variable-length arrays cannot be ivars).

Related

Creating a private 2D float array - Objective C

I am tring to create a private 2D float array and initialize it in constructor. I am getting "Expected Expression" error. I searched for a long while and couldn't find anything.
Here is my code:
#interface SampleClass : NSObject{
#private
float stops[2][2];
}
#end
#implementation SampleClass
- (id) init{
self = [super init]; // Edited
stops = { {1.0, 1.0}, {1.0, 2.0} }; // It gives "Expected Expression" at this line
return self;
}
#end
I tried different versions like:
stops = { {1.0, 1.0}, {1.0, 2.0} };
stops = { 1.0, 1.0, 1.0, 2.0 };
stops[][] = { {1.0, 1.0}, {1.0, 2.0} };
Non of them seems to work.
I am new to Objective C so any recommendation is appreciated.
(Objective-)C does not support assignment of one array to another, there are workarounds involving struct as they are assignable but you don't need to go there.
If you are after a constant array to be used by instances you can just declare it as static:
static const float stops[2][2] = { {27.3, 51.7}, {93.2, 42.24}};
The static makes stops accessible only to code within the same file. You can place the declaration between the #implementation and #end to at least visually associate it as belonging to a class.
The above is not suitable if you need a variable array, but does form part of a solution. Keep your instance variable:
#private
float stops[2][2];
This must be an array, not some pointer, as it must allocate the space for your floats. Next use the above declaration but give it a different name:
static const float _stops_init[2][2] = { {27.3, 51.7}, {93.2, 42.24}};
and then in your init use the standard C function memcpy() to copy the values in the memory occupied by _stops_init into the memory occupied by stops:
memcpy(stops, _stops_init, sizeof(_stops_init));
Here sizeof() will return the total size in bytes of the memory used by your float array _stops_init and memcpy() copies those bytes over those associated with stops – that is it implements array assignment which C doesn't directly support.
Using the static const array rather than a local variable define in init() as the source of your values saves re-creating the source on every call to init().
The above code doesn't do all the checks it should - at minimum an assert() checking that the sizes of stops and _stops_init are the same is advisable.
HTH

float array gives different datas at the end of it in objective c

I bumped to a strange error.(at least for me) I am trying to use float array in FFT and audio filters that I apply. but float array gives different datas at the end.
I define a global pointer. I point a float array to it. but when I try to use the pointer in somewhere out of the scope of a method, the last 100-150 datas of 441000 datas get mostly 0 or some other very big numbers. I dont understand how a data can change when I use somewhere in out of scope
in scope I loop in it and every data is correct but when I try to loop outside of the scope of the method I created the array, it gives different datas at the end.
#interface ViewController ()
{
float *filteredData;
int theFileLengthInFrames;
}
#end
#implementation ViewController
..
..
-(void)FilterData:(float * ) rawData
{
int count = theFileLengthInFrames;
float filteredRawData[count];
for (int i = 0; i<count; i++)
{
filteredRawData[i] = rawData[i];
printf("%d_%f ",i,filteredRawData[i]);
//I check here to see the data . In here it is normal
}
filteredData = filteredRawData;
}
-(void) CalculateFFT
{
int numSamples = theFileLengthInFrames;
for (int i = 0; i<numSamples; i++)
{
printf("%d_%f ",i,filteredData[i]);
//when I check here to see the data , the last around 100 data are 0.00000 or some big number such as 250399682724883753288597504.000000
}
}
need help thanks
Your FilterData: method points the instance variable filteredData to a local array filteredRawData. Since filteredRawData is allocated on the stack, it becomes invalid when FilterData: returns. Then filteredData is a dangling pointer, and using it results in undefined behavior.
Solution: allocate persistent storage for filteredData. I would do it like this:
#implementation ViewController {
NSMutableData *filteredDataStorage;
float *filteredData;
}
-(void)FilterData:(float * ) rawData {
int count = theFileLengthInFrames;
filteredDataStorage = [NSMutableData dataWithLength:count * sizeof *rawData];
filteredData = (float *)filteredDataStorage.mutableBytes;
for (int i = 0; i<count; i++) {
filteredRaw[i] = rawData[i];
printf("%d_%f ",i,filteredRawData[i]);
//I check here to see the data . In here it is normal
}
}
Using NSMutableData for the persistent storage lets ARC take care of deallocating it when you call FilterData: again, or when ViewController is deallocated.
filteredData - The float pointer is an ivar, it's scoped to your object instance.
filteredRawData is defined at method scope. It's an array located on the stack. When filteredRawData goes out of scope that memory is no longer valid. Reading from it is undefined at best and could result in an access violation. You probably want to use malloc to dynamically allocate memory for your data, or have a global buffer defined for you to play with.

Setting values in a custom struct as property in Objective-C [duplicate]

This question already has answers here:
Mixing C Structs and Objective-C Properties
(2 answers)
Closed 8 years ago.
I have class A with a header that looks something like this:
typedef struct {
int x;
int y;
} Position;
#interface ClassA : NSObject
#property Position currentPosition;
#end
And I try to assign individual values of the position struct from the property in another class like this:
ClassA * classA = [ClassA new];
classA.currentPosition.x = 10;
Which gives an error "expression is not assignable" and won't compile.
I can set it like this:
ClassA * classA = [ClassA new];
Position position = {
.x = 1,
.y = 2
};
classA.currentPosition = position;
And I can even alter individual "properties" of position variable like this:
ClassA * classA = [ClassA new];
Position position = {
.x = 1,
.y = 2
};
// WORKS
position.x = 4;
// DOESN'T WORK
// classA.currentPosition.x = 4;
classA.currentPosition = position;
Why can't I set values individually when they are a property?
This expression:
classA.currentPosition
returns a temporary copy of your struct, not the struct itself. The compiler error is telling you that you can't assign a value to some member of that temporary copy (because it's an rvalue, technically). But you don't want to assign a value to that member anyway, because it would just disappear along with the struct itself.
So why are you only getting a copy of the struct in the first place?
Because
#property Position currentPosition
is actually just shorthand for:
-(Position)currentPosition;
-(void)setCurrentPosition(Position value);
and in C-family languages, the first line (the getter) indicates that it's returning a Position struct by-value, or as a copy.
You could make your own accessor that returns a reference, but you probably shouldn't. This isn't a common idiom in Objective-C -- at least not in this context -- and you should generally try to stick with common idioms for a language.
Instead, you should use position like the following;
Position pos = classA.position;
pos.x = 4;
classA.position = pos;
Lastly, if you really want to be able to set currentPosition using the syntax you originally desired, while maintaing Objective-C idioms, you could just make Position a class rather than a struct. Then, the property can return a Position * and the rest of the syntax would work. Make sure to initialize the pointer in your init function (or when appropriate).
Properties don't work for C structs.
You can do it like:
#property Position *currentPosition;
Basically, using a pointer.
Now you actually need to initialize that pointer so:
- (id) init {
self = [super init];
if(self){
self.currentPosition = malloc(sizeof(Position));
}
return self;
}
Then, don't forget to use arrow notation, since you're dealing with a pointer:
classA.currentPosition->x = 5;
And don't forget to free the memory you requested!
-(void)dealloc{
free(self.currentPosition);
}

Returning a 2D C array from an Objective-C function

I want to do achieve something like this in Objective-C
+(int[10][10])returnArray
{
int array[10][10];
return array;
}
However, this gives an "array initializer must be an initializer list" compiler error. Is this at all possible?
You can't return an array (of any dimension) in C or in Objective-C. Since arrays aren't lvalues, you wouldn't be able to assign the return value to a variable, so there's no meaningful for such a thing to happen. You can work around it, however. You'll need to return a pointer, or pull a trick like putting your array in a structure:
// return a pointer
+(int (*)[10][10])returnArray
{
int (*array)[10][10] = malloc(10 * 10 * sizeof(int));
return array;
}
// return a structure
struct array {
int array[10][10];
};
+(struct array)returnArray
{
struct array array;
return array;
}
Another way you can do it with objective C++, is to declare the array as follows:
#interface Hills : NSObject
{
#public
CGPoint hillVertices[kMaxHillVertices];
}
This means the array is owned by the Hills class instance - ie it will go away when that class does. You can then access from another class as follows:
_hills->hillVertices
I prefer the techniques Carl Norum describes, but wanted to present this as an option that might be useful in some cases - for example to pass data into OpenGL from a builder class.

2d arrays of ints in objective-c

I am working with C style 2d arrays of integers.
This is fine in my main class file, and I can pass my arrays by reference to other classes. I have run into issues when I try to retrieve a pointer to the arrays and work with that.
My question is: rather than using C style 2d arrays, is there a better way to do it? maybe a Cocoa class I don't know about? I noticed NSMatrix, but that seems geared for cells, rather than plain ints.
I've got calls all over the place in this format: items[x][y], so a shorthand way of referencing array positions would be great.
Further details:
I set up the arrays as instance variables, and tried to access like this:
-(void) setItems: (int [15][24])items
{
(*pitems)[24] = **items;
}
-(int) getItems
{
return (*pitems)[24];
}
When I tried to retrieve using getItems, I was getting compiler warnings about creating a reference without a cast.
An interesting discussion here: http://www.idevapps.com/forum/archive/index.php/t-244.html
Basically the suggestion was to turn your 2D array into multiple 1D arrays. For Example:
int array[20][8] becomes
int** array = (int*)malloc(20 * sizeof(int*));
unsigned int i = 0;
for (i = 0; i < 20; ++i)
{
array[i] = (int)malloc(8 * sizeof(int));
}
and your method returns int** and variable is of type int**.
This has the advantage that normal 2D array indexing works as expected.
The other option that wasn't suggested in the link was to use a NSMutableArray of type NSMutableArray. This would be slower than standard C arrays, but easier to pass around and reference.
You can only pass around 2D static arrays if you know the exact size of the first dimension:
// OK, even though we don't know the size of the second dimension
- (void) doStuff: (int [15][])array { ... }
...
int array[15][24];
[self doStuff:array];
// ERROR: don't know size of first dimension (second dimension is irrelevant)
- (void) doStuff: (int [][])array { ... }
Of course, then your function only works for one particular array size in the first dimension. If you won't know the size if your first dimension until runtime, you'll have to either flatten your array into a 1D array, or use a dynamically allocated array of pointers to 1D arrays as in KiwiBastard's answer.