Why do I get the error "Array initializer must be an initializer list" when I'm trying to return this array in a function? - objective-c

I am coming from Java, and I'm very new to Objective C. Anyway, I have this static method which is designed to make a copy of an array (if there's a better way to accomplish this, please let me know, but I'm asking this question more-so to find out why I got this error and how to avoid such an error in the future.) I ran into some problems with it, but just when I thought I had them all sorted out, I got this error that looked like
Here is the method in the interface:
+ (float[]) copyArray: (float[]) array withLength: (int) length;
And here is the method in the implementation:
+ (float[]) copyArray: (float[]) array withLength: (int) length
{
float copiedArray[length];
for (int i = 0; i < length; i++)
{
copiedArray[i] = array[i];
}
return copiedArray;
}

If all you really want is to copy the first n elements from one C array into another already existing array, probably the best way is to simply use memcpy:
memcpy(targetArray, sourceArray, sizeof(sourceArray[0]) * numElements);
The sizeof(sourceArray[0]) calculates the byte-size of the type in your array (in your case, it's equivalent to sizeof(float).

method/function cannot return C array. you should do this
+ (void) copyArrayFrom:(float *)array to:(float *)toArray withLength: (unsigned) length
{
for (int i = 0; i < length; i++)
{
toArray [i] = array[i];
}
}

C arrays are way more tricky than Java arrays. One of the biggest issues is that in a lot of instances, you don't know how large a C array is unless you have saved this information in a different variable, for example. The C FAQ "Arrays and Pointers" lists a lot of traps and they apply to Objective-C as well. You might want to see question 6.5 in particular.
As #lwxted already suggested, try to avoid C arrays unless you really know what you're doing and you have determined that you need them. C arrays are faster than NSArray but unless you have determined that your array really is a performance bottleneck by measuring with a profiler you will most likely not notice any difference.
And I strongly recommend avoiding a C array of Objective-C objects (id objects[]) unless you really, really know very well what you are doing (memory management issues).

In Objective-C, unless for particular needs, a better way to handle this usually is to use the NSArray as opposed to C arrays.
[NSArray arrayWithArray: array];
will copy an array.
Besides, in this case, if you insist on using C arrays, the use of implicitly typed length float[] is advised against. A better way is to use pointers to manipulate arrays.
Also, the stack-allocated array would be invalid after leaving the function, since it's local only in the scope of the copyArray function. You should dynamically allocate memory, if you wish the array to be valid outside the scope.

While I agree with all the points #DarkDust makes, if you're working with a C API such as OpenGL, there may be situations where using NSArray and NSNumber vs. C arrays of type float will have performance impacts. As always, try to use the simpler approach first, and carefully measure performance before deciding to optimize.
In any case, to answer the original question, here's how to correctly return a copy of a C array:
+ (float *)copyOfCArray:(float *)array withLength:(int)length
{
float *copyOfArray = malloc(length * sizeof(float));
for (int i = 0; i < length; i++) {
copyOfArray[i] = array[i];
}
return copyOfArray;
}
Also, there's arguably no need to make the above a method at all. Instead, consider writing it as a C function:
float *CopyArray(float *array, int length)
{
// Implementation would be the same...
}

Related

Creating a dynamic 2D pointer array of NSObjects in Objective C

I want to store a 2D array of NSObjects using C pointer arrays. I read another StackOverflow question which said that it's possible to do this as follows:
id myArray [10][10];
However I want to allocate the memory dynamically because I don't know how big the table will be before hand.
I understand how to create a 2D pointer array for standard C variable types but I don't know how to do it for the id type. If I were using an int, I'd do something like this:
int ** myArray = (int**) calloc (10, sizeof(int*));
for(int i = 0; i<10; i++) {
myArray[i] = (int *) calloc(10, sizeof(int));
}
Any ideas how to do this with the id data type?
If you're using ARC (which you probably should be) creating a C array of id type objects is going to be more trouble than it's worth. You need to both calloc and free the array in the usual (non id way) and you also need to annotate the id objects like id __strong myArray = … The other thing that's really counterintuitive but is required to make sure the elements in myArray are deallocated correctly is to explicitly set each element of myArray to nil before you free myArray.
So anyway, it's a lot of trouble and there are several gotchas to work around. You should just use an NSMutableArray of NSMutableArrays. With the latest versions of llvm you can still access the arrays using "C style" syntax, like myArray[x][y] = someObject;.

Strange for loops I'm not familiar with: "for (id * in *)"

I apologize if this question is exceedingly simple, but I've Googled like crazy and am unable to find a suitable explanation for what this is.
for (id line in self.lines){
[linesCopy addObject:[line copyWithZone:zone]];
}
I'm just learning Objective-C, and this is a form of for loop that I've never seen before. I'm familiar with the simple
for (int x = 1, x < 10, x++)
style of for loop.
From Cocoa Core Competencies: Enumeration:
Fast Enumeration
Several Cocoa classes, including the collection classes, adopt the NSFastEnumeration protocol. You use it to retrieve elements held by an instance using a syntax similar to that of a standard C for loop, as illustrated in the following example:
NSArray *anArray = // get an array;
for (id element in anArray) {
/* code that acts on the element */
}
As the name suggests, fast enumeration is more efficient than other forms of enumeration.
In case you didn't know, id is an Objective-C type that basically means “a pointer to any Objective-C object”. Note that the pointer-ness of id is built in to it; you usually do not want to say id *.
If you expect the elements of anArray to be of a specific class, say MyObject, you can use that instead:
for (MyObject *element in anArray) {
/* code that acts on the element */
}
However, neither the compiler nor the runtime will check that the elements are indeed instances of MyObject. If an element of anArray is not an instance of MyObject, you'll probably end up trying to send it a message it doesn't understand, and get a selector-not-recognized exception.
It's the shorthand equivalent of this common form:
for (int i = 0; i < [self.lines count]; i++) {
id line = [self.lines objectAtIndex:i];
// ...
}
It's such a common looping idiom (walking through some collection, array, set, etc. an item at a time), that it's been turned into a shorthand form like this, called "fast enumeration".
In fact, in its internal implementation, it's actually slightly more faster than doing it yourself, so it's preferable both for clarity and performance.
It's a statement that can be used with classes that are conform to NSFastEnumeration protocol. When you have this available, the Objective-C programming guide suggest you to use it. Take a look here. It's a way to iterate over a collection without the traditional for (int i = 0; i < length; ++i) syntax.
Mind that it doesn't usually support deleting and inserting elements while iterating through this way (also by using normal for loops you should take care about indices in any case).
Basically all standard collections supports this way of iteration.
It's called a forin loop, also called fast enumeration. Basically, the syntax is:
for (SomeObjectIAmExpecting *localVariableName in anArrayOfObjects)
{
if (![localVariableName isKindOfClass:[SomeObjectIAmExpecting class]]) continue; //To avoid errors.
//do something to them
}

Objective-C ARC and passing C arrays of objects

I'm sorry if this is a bit of a C-noob question: I know I need to swot up on my pointers. Unfortunately I'm on a deadline so don't have time to work through a whole book chapter, so I'm hoping for a bit more targeted advice.
I want to store some objective-C objects in a C array. I'm using ARC. If I were on the Mac I'd be able to use NSPointerArray instead, but I'm on iOS and that's not available.
I'll be storing a three-dimensional C array: conceptually my dimensions are day, height, and cacheNumber. Each element will either be a pointer to an objective-C object, or NULL.
The number of caches (i.e. the size of the cacheNumber dimension) is known at compile time, but the other two are not known. Also, the array could be very large, so I need to dynamically allocate memory for it.
Regarding ownership semantics, I need strong references to the objects.
I would like the whole three-dimensional array to be an instance variable on an objective-C object.
I plan to have a method that is - tableForCacheNumber:(int)num days:(int*)days height:(int*)height. That method should return a two-dimensional array, that is one specific cache number. (It also passes back by reference the size of the array it is returning.)
My questions:
What order should I put my dimensions so that I can easily return a pointer to the subarray for one specific cache number? (I think it should be first, but I'm not 100%.)
What should the return type of my method be, so that ARC doesn't complain? I don't mind if the returned array has an increased reference count or not, as long as I know which it's doing.
What type should my instance variable that holds the three dimensional array be? I think it should just be a pointer, since that ivar just represents the pointer to the first item that's in my array. Correct? If so, how do I specify that?
When I create the three-dimensional array (for my ivar), I guess I do something like calloc(X * Y * Z, sizeof(id)), and cast the result to the type for my ivar?
When accessing items from the three-dimensional array in the ivar, I believe I have to dereference the pointer each time, with something like (*myArray)[4][7][2]. Correct?
Will the two-dimensional array I return from the method be similarly accessed?
Do I need to tag the returned two-dimensional array with objc_returns_inner_pointer?
I'm sorry once again that this is a bit of a bad Stack Overflow question (it's too long and with too many parts). I hope the SO citizens will forgive me. To improve my interweb karma, maybe I'll write it up as a blog post when this project has shipped.
First off: while you don't have NSPointerArray, you do have CFMutableArrayRef and you can pass any callbacks you want for retain/release/description, including NULL. It may be easier (and performance is something you can measure later) to try that first.
Taking your points in order:
you should define your dimensions as [cacheNumber][days][height], as you expect. Then cache[cacheNumber] is a two-dimensional array of type id *[][]. As you've said performance is important, be aware that the fastest way to iterate this beast is:
for (/* cacheNumber loop */) {
for (/* days loop */) {
for (/* height loop */) {
//...
}
}
}
it should be of type __strong id ***: that's a pointer to a pointer to a pointer to id, which is the same as array of (array of (pointer to id)).
your ivar needs to be __strong id **** (!), because it's an array of the above things.
you guess incorrectly regarding allocating the array.. If you're using a multidimensional array, you need to do this (one dimension elided for brevity):
- (__strong id * * *)someArray {
__strong id * * *cache = (__strong id * * *)malloc(x*y*sizeof(void *));
id hello = #"Hello";
cache[0] = (__strong id * *)malloc(sizeof(void *)); //same for cache[1..x-1]
cache[0][0] = &hello; // for all cache[x][y]
return (__strong id * * *)cache;
}
correct, that is how you use such a pointer.
yeah, the two-D array works in the same way, sans the first dimension.
I don't think so, you're handing out __strong object pointers so you should be grand. That said, we're at about the limit of my ability with this stuff now so I could well be wrong.
Answering my own question because this web page gave me the missing bit of info I needed. I've also upvoted Graham's answer, since he was very helpful in getting my head round some of the syntax.
The trick I was missing is knowing that if I want to refer to items in the array via the array[1][5][2] syntax, and that I don't know the sizes of my array at compile time, I can't just calloc() a single block of data for it.
The easiest to read (although least efficient) method of doing that is just with a loop:
__strong Item ****cacheItems;
cacheItems = (__strong Item ****)calloc(kMaxZooms, sizeof(Item ***));
for (int k = 0; k < kMaxZooms; k++)
{
cacheItems[k] = (__strong Item ***)calloc((size_t)daysOnTimeline, sizeof(Item **));
for (int j = 0; j < daysOnTimeline; j++)
{
cacheItems[k][j] = (__strong Item **)calloc((size_t)kMaxHeight, sizeof(Item *));
}
}
I'm allocating a three dimensional array of Item *s, Item being an objective-C class. (I have of course left out the error handling code in this snippet.)
Once I've done that, I can refer to my array using the square brackets syntax:
cacheItems[zoom][day][heightToUse] = item;
The web page I linked to above also describes a second method for performing the memory allocations, that uses only one call to calloc() per dimension. I haven't tried that method yet, as the one I've just described is working well enough at the moment.
I would think of a different implementation. Unless it is a demonstrable (i.e. you have measured and quantified it) performance issue, trying to store Objective-C objects in plain C arrays is often a code smell.
It seems to me that you need an intermediate container object which we will call a Cache for now. One instance will exist for each cache number, and your object will hold an NS(Mutable)Array of them. Cache objects will have properties for the maximum days and height.
The Cache object would most easily be implemented with an NSArray of the objects in it, using simple arithmetic to simulate two dimensions. Your cache object would have a method -objectAtDay:Height: to access the object by its coordinates.
This way, there is no need at all to worry about memory management, ARC does it for you.
Edit
Given that performance is an issue, I would use a 1D array and roll my own arithmetic to calculate offsets. The type of your instance variable would be:
__strong id* myArray;
You can only use C multilevel subscripts (array[i][j][k]) if you know the range of all the dimensions (except the first one). This is because the actual offset is calculated as
(i * (max_j * max_k) + j * max_k + k) * sizeof(element type)
If the compiler doesn't know max_j and max_k, it can't do it. That's precisely the situation you are in.
Given that you have to use a 1D array and calculate the offsets manually, the Apple example will work fine for you.

Objective-C, C type Arrays, and OpenGL ES 2.0

I'm not exactly sure how to ask this, or if it's been asked before...
So here we go:
I'm trying to write a game in Objective-C for iOS. One main feature of this game is the ability to morph the 2D landscape (technically 3D, however it starts out as a flat, 2D plain with points scattered throughout it to make a perfect mesh of 20 1x1 squares) to the user's liking; however, in Objective-C, apparently you cannot pass C-Typed arrays through methods.
e.g:
-(VertexS *) getVertexArrayData {
VertexS myArray[definedAmount]; //VertexS being a structure
for (int i = 0; i != definedAmount; i++) {
myArray[i] = vertexData;
}
return *myArray;
}
//In the other file (the one with all my rendering), under a different class, inside a method
//Lets pretend the aforementioned method was under a class called "Terrain"
-(id) initWithFrame:(CGRect)frame
{
terrain = [[[Terrain alloc] init] autorelease];
[terrain constructLand];
VertexS *_vertexData = [terrain getVertexArrayData];
... etc.
}
Apparently, it doesn't work. Not saying that that is exactly what I'm doing, but very similar. What happens in my exact code is I use an ivar to hold the vertex/index data after it gets info from the other method.
Considering OpenGL (ES) requires either a vector container (well, in C++), or a C type Array (which is technically the same thing) in order to correctly create an IBO/VBO, I'm at a loss. I've been fiddling with it for almost a day and a half now, unable to get around the problem, and too (mentally) fat to learn NSMutableArrays--unless suggested by you, the wonderful community, in which I will pseudo-miraculously lose enough weight to learn NSMutableArrays (probably better said as "I will stop avoiding the unfamiliar solution,").
I can't actually remember my other question... Mreh. It probably isn't relavent but if I remember I will find a way to ask it.
Anyways, any help is requested. I don't know what else I can possibly do to get around this road block in my project.
Objective-C is a superset of the C language, so anything you can do in plain C will also work in Objective-C. The myArray array is declared on the stack in -getVertexArrayData. It gets abandoned when the method returns and that memory is available for reuse by the next function call. To fix this, allocate the array on the heap using malloc() (or one of its relatives).
-(VertexS *) getVertexArrayData {
VertexS *myArray = malloc(definedAmount * sizeof(VertexS));
for (int i = 0; i < definedAmount; i++) {
myArray[i] = vertexData;
}
return myArray;
}
C-style memory management doesn't use reference counting, so don't forget to free the array when you're done with it:
free(_vertexData);

Replace array with another array in C

Out of pure curiosity, I started playing with array's in ways that I have never used before. I tried making a data structure array, and set it equal to another:
typedef struct _test {
float value;
} test;
Simple enough struct, so I tried this:
test struct1[10];
test struct2[20];
struct1 = struct2;
I didn't think this would work, and it didn't even compile. But, this interests me a lot. Is it possible to take an array of 10 and increase the size to 20, while copying the data?
Objective-C
I am actually doing this with Objective-C, so I'd like to hear from the Objective-C people as well. I want to see if it is possible to change the size of struct1 in this file.
#interface Object : NSObject {
test struct1;
}
Remember: This is only out of curiosity, so everything is open to discussion.
Something else that is not exactly pertinent to your question but is interesting nonetheless, is that although arrays cannot be assigned to, structs containing arrays can be assigned to:
struct test
{
float someArray[100];
};
struct test s1 = { /* initialise with some data*/ };
struct test s2 = { /* initialise with some other data */ };
s1 = s2; /* s1's array now contains contents of s2's array */
This also makes it possible to return fixed-length arrays of data from functions (since returning plain arrays is not allowed):
struct test FunctionThatGenerates100Floats(void)
{
struct test result;
for (int i = 0; i < 100; i++)
result.someArray[i] = randomfloat();
return result;
}
As others have said, arrays allocated like that are static, and can not be resized. You have to use pointers (allocating the array with malloc or calloc) to have a resizable array, and then you can use realloc. You must use free to get rid of it (else you'll leak memory). In C99, your array size can be calculated at runtime when its allocated (in C89, its size had to be calculated at compile time), but can't be changed after allocation. In C++, you should use std::vector. I suspect Objective-C has something like C++'s vector.
But if you want to copy data between one array and another in C, use memcpy:
/* void *memcpy(void *dest, const void *src, size_t n)
note that the arrays must not overlap; use memmove if they do */
memcpy(&struct1, &struct2, sizeof(struct1));
That'll only copy the first ten elements, of course, since struct1 is only ten elements long. You could copy the last ten (for example) by changing &struct2 to struct2+10 or &(struct2[10]). In C, of course, not running off the end of the array is your responsibility: memcpy does not check.
You can also you the obvious for loop, but memcpy will often be faster (and should never be slower). This is because the compiler can take advantage of every trick it knows (e.g., it may know how to copy your data 16 bytes at a time, even if each element is only 1 byte wide)
You can't do this in C with static arrays, but you can do it with dynamically allocated arrays. E.g.,
float *struct1, *struct2, *struct3;
if(!(struct1 = malloc(10 * sizeof(float))) {
// there was an error, handle it here
}
if(!(struct2 = realloc(struct1, 20 * sizeof(float))) {
// there was an error, handle it here
// struct1 will still be valid
}
if(!(struct3 = reallocf(struct2, 40 * sizeof(float))) {
// there was an error, handle it here
// struct2 has been free'd
}
In C, I believe that's a good place to use the realloc function. However, it will only work with dynamically allocated arrays. There's no way to change the memory allocated to struct1 by the declaration test struct1[10];.
In C arrays are constants, you can't change their value (that is, their address) at all, and you can't resize them.
Clearly if you declare your array with a fixed size, test struct1[10] then it cannot be resized. What you need to do is to declare it as a pointer:
test *struct1;
Then you must use malloc to allocate the array and can use realloc to resize it whilst preserving the contents of the original array.
struct1 = malloc(10*sizeof(*struct1));
//initialize struct1 ...
test *struct2 = realloc(struct1, 20*sizeof(*struct1));
If you're using Objective C, you know you can just use NSMutableArray, which automatically does the realloc trick to reallocate itself to store however many objects you put in it, up the limit of your memory.
But you're trying to do this with struct? What would that even mean? Suppose you increase the amount of memory available to struct1 in Object. It's still a struct with one member, and doesn't do anything more.
Is the idea to make Object be able to contain an expanded struct?
typedef struct _test2 {
float value;
NSObject *reference;
} test2;
But then you still can't access reference normally, because it's not a known part of Object.
Object *object2;
...
NSLog(#"%#", object2.struct1.reference); // does not compile
If you knew you had one of your modified objects, you could do
Object *object2;
...
NSLog(#"%#", ((test2)(object2.struct1)).reference);
And also you could still presumably pass object2 to anything that expects an Object. It only has any chance of working if struct1 is the last member of Object, and don't mess with subclassing Object either.
Some variety of realloc trick might then work, but I don't think realloc in particular, because that's intended to be used on objects that are allocated with malloc, and the details of what C function is used to allocate objects in not exposed in Objective C, so you shouldn't assume it's malloc. If you override alloc then you might be able to make sure malloc is used.
Also you have to watch out for the fact that it's common in Objective C for more than one pointer to an object to exist. realloc might move an object, which won't be semantically correct unless you correct all the pointers.