Passing NSArray to a cpp function - objective-c

I need to call a cpp function like
void myFunc(float **array2D, int rows, int cols)
{
}
within an objective-c object. Basically, the array is created in my objective-c code as I create an NSArray object. Now, the problem is how to pass this array to my cpp function.
I am a bit new to these mixed c++/objective-c stuffs so any hint will be highly appreciated.
Thanks

I guess you have to convert the NSArray to a plain C array.
Something like:
NSArray *myNSArray; // your NSArray
int count = [myNSArray count];
float *array = new float[count];
for(int i=0; i<count; i++) {
array[i] = [[myNSArray objectAtIndex:i] floatValue];
}
or, as a commenter suggested (assuming your NSArray contains NSNumbers):
NSArray *myNSArray; // your NSArray
int count = [myNSArray count];
float *array = new float[count];
int i = 0;
for(NSNumber *number in myNSArray) {
array[i++] = [number floatValue];
}

Look at this post.
Check out the answer that mentions using [NSArray getObjects] to create a c-style array.
Here's the code that the poster put in there:
NSArray *someArray = /* .... */;
NSRange copyRange = NSMakeRange(0, [someArray count]);
id *cArray = malloc(sizeof(id *) * copyRange.length);
[someArray getObjects:cArray range:copyRange];
/* use cArray somewhere */
free(cArray);

Alternately, since CFArray is toll-free bridged to NSArray, could you call those C functions from your C++ function? I'd look around, wouldn't be surprised if there weren't a C++ wrapper to give similar semantics, or one could be written easily enough.

Related

property for ivar that points to two-dimensional array of pointers to NSStrings

I want to create a class that contains a dynamic, two-dimensional c-array of pointers to NSStrings. I know I can simulate a two-dimensional array using an NSArray containing multiple NSArrays, but if possible I'd like to do this using a traditional two-dimensional c-array. ARC won't allow a simple assignment of a pointer to an NSString to an element of a c-array unless you use "__unsafe_unretained":
#interface NumberStringsArray : NSObject
{
#public
NSString * __unsafe_unretained **_array;
}
To avoid memory leaks and to give an object in the class ownership of each NSString assigned to the c-array, I add a pointer to each NSString object to an NSMutableArray. In -(void)dealloc I free the memory acquired to create the two-dimensional c-array.
Here's my question: How do I declare a property based on the _array ivar so that I can refer to the i,j element of the array as "foobar.array[i][j]" rather than "foobar->array[i][j]"?
Later amplification: I did it in a very similar manner to the answerer except for the __bridge stuff. I don't know if that makes a difference. I allocate the two-dimensional array here:
self->_array = (NSString * __unsafe_unretained **)calloc(_columnCount, sizeof(void *));
if (!self->_array)
return nil;
for (UINT16 i = 0; i < _columnCount; i++)
{
self->_array[i] = (NSString * __unsafe_unretained *)calloc(_rowCount, sizeof(void *));
if (!self->_array[i])
{
for (UINT16 a = 0; a < _columnCount; a++)
if (self->_array[a])
free(self->_array[a]);
if (self->_array)
free(self->_array);
return nil;
}
}
I put pointers to the NSString objects into the array using substrings generated from a file of comma-separated values:
NSArray *numbers = [line componentsSeparatedByString: #","];
for (UINT16 i = 0; i < _columnCount; i++)
{
NSString *number = #"";
if (i < [numbers count])
number = [numbers objectAtIndex: i];
//
// save it in owners
//
[self.owners addObject: number];
self->_array[i][j] = number;
}
In -(void)dealloc I free all the memory:
-(void)dealloc
{
for (UINT16 i = 0; i < self.columnCount; i++)
if (self->_array[i])
free(self->_array[i]);
if (self->_array)
free(self->_array);
}
Declare this property:
#property (nonatomic) NSString * __unsafe_unretained **_array;
Then you can allocate the pointers to objects:
_array= (NSString * __unsafe_unretained **) malloc(M*sizeof(CFTypeRef) );
for(NSUInteger i=0; i<M;i++)
{
_array[i]= ((NSString * __unsafe_unretained *) malloc(N*sizeof(CFTypeRef) );
for(NSUInteger j=0; j<N;j++)
{
_array[i][j]= (__bridge NSString*) (__bridge_retained CFTypeRef) [[NSString alloc]initWithCString: "Hello" encoding: NSASCIIStringEncoding];
// I see that you got habit with C so you'll probably like this method
}
}
Then when you don't need it anymore, free the array:
for(NSUInteger i=0; i<M; i++)
{
for(NSUInteger j=0; j<N;j++)
{
CFTypeRef string=(__bridge_transfer CFTypeRef) _array[i][j];
}
free(_array[i]);
}
free(_array);
You can't because you can't declare a concrete object for an Objective-C class. So
NumberStringsArray object;
is not allowed.
You are forced to declare it as
NumberStringsArray *object = [[NumberStringsArray alloc] init.. ];
so you have to access to the ivar through the correct -> operator applied to pointers. Mind that the object.something in Objective-C is just a shorthand for [object something] while in standard C you would use . to access to fields of a concrete struct.
(Note: This addresses the creation/use of the property to access the data, not the way the data should be managed by conventional Objective-C storage management or by ARC. Thinking about that makes my head hurt.)
If you want a read-only C array to "look" like an Objective-C property, declare the property such as #property (readonly, nonatomic) char* myProp; and then, rather than using #synthesize, implement a getter for it along the lines of:
-(char**)myProp {
return myPropPointer;
// Or, if the array is allocated as a part of the instance --
return &myPropArray[0];
}

How can I pass a C array to a objective-C function?

I'm not familiar with C. How can I pass a C array to a Objective-C function ?
I actually need an example of a class function converting NSArray to C arrays.
This is what I have so far:
+ (NSArray *)convertArray:(NSString*)array { //I don't think this is correct: the argument is just a NSString parameter and not an array
NSMutableArray * targetArray = [NSMutableArray array];
for (i = 0; i < SIZE; i++) //SIZE: I dunno how to get the size of a C array.
{
[targetArray addObject: [NSString stringWithString:array[i]];
}
return targetArray;
}
There are a few ways.
If your array size is fixed at compile-time, you can use the C99 static modifier:
-(void) doSomething:(NSString *[static 10]) arg
{
}
If not, you have to pass it as two separate arguments. One as a pointer to the first element of it, and the second as the length of it:
-(void) doSomething:(NSString **) arg count:(size_t) count
{
}
Now you can access your variables like any other array you may have.
Because you are dealing with a C-array of objective-c objects, you can actually use NSArray's built in constructor for turning a C-array into a NSArray:
NSArray *result = [NSArray arrayWithObjects:arg count:count];

Looping using NSRange

I'm trying to use NSRange to hold a range of years, such as
NSRange years = NSMakeRange(2011, 5);
I know NSRange is used mostly for filtering, however I want to loop over the elements in the range. Is that possible without converting the NSRange into a NSArray?
It kind of sounds like you're expecting NSRange to be like a Python range object. It's not; NSRange is simply a struct
typedef struct _NSRange {
NSUInteger location;
NSUInteger length;
} NSRange;
not an object. Once you've created one, you can use its members in a plain old for loop:
NSUInteger year;
for(year = years.location; year < NSMaxRange(years); year++ ){
// Do your thing.
}
(Still working on the assumption that you're thinking about Python.) There's syntax in ObjC called fast enumeration for iterating over the contents of an NSArray that is pleasantly similar to a Python for loop, but since literal and primitive numbers can't be put into an NSArray, you can't go directly from an NSRange to a Cocoa array.
A category could make that easier, though:
#implementation NSArray (WSSRangeArray)
+ (id)WSSArrayWithNumbersInRange:(NSRange)range
{
NSMutableArray * arr = [NSMutableArray array];
NSUInteger i;
for( i = range.location; i < NSMaxRange(range); i++ ){
[arr addObject:[NSNumber numberWithUnsignedInteger:i]];
}
return arr;
}
Then you can create an array and use fast enumeration:
NSArray * years = [NSArray WSSArrayWithNumbersInRange:NSMakeRange(2011, 5)];
for( NSNumber * yearNum in years ){
NSUInteger year = [yearNum unsignedIntegerValue];
// and so on...
}
Remember that a NSRange is a structure holding two integers, representing the start and length of the range. You can easily loop over all of the contained integers using a for loop.
NSRange years = NSMakeRange(2011, 5);
NSUInteger year;
for(year = years.location; year < years.location + years.length; ++year) {
// Use the year variable here
}
This is a bit of an old question, but an alternative to using an NSArray would be to create an NSIndexSet with the desired range (using indexWithIndexesInRange: or initWithIndexesInRange:) and then using block enumeration as in https://stackoverflow.com/a/4209289/138772. (Seemed relevant as I was just checking on this myself.)
My alternate solution for this, was to define a macro just to make shorthand quicker.
#define NSRangeEnumerate(i, range) for(i = range.location; i < NSMaxRange(range); ++i)
To call it you do:
NSArray *array = #[]; // must contain at least the following range...
NSRange range = NSMakeRange(2011, 5);
NSUInteger i;
NSRangeEnumerate(i, range) {
id item = array[i];
// do your thing
}
personally I am still trying to figure out how I can write the macro so I can just call it like:
NSRangeEnumerate(NSUInteger i, range) {
}
which is not supported just yet... hope that helps or makes typing your program quicker

Declare Dynamic Array

How can I declare dynamic array? For example:
int k=5;
I want to have an array like below:
int myArray[k];
if i read the question right.. (unlikely at this point)
NSMutableArray *myArray = [[NSMutableArray alloc] initWithCapacity:k];
Sometimes true arrays (not NSArray) are really needed. See for example indexPathWithIndexes:length: in NSIndexPath, it take array of uintegers as parameter. For array allocation you should use the following approach:
NSUInteger *arr = (NSUInteger*)malloc(elementsCount * sizeof(NSUInteger) );
arr[0] = 100;
free(arr);
In Objective-C, the standard way to do this is to use the NSMutableArray class. This is a container that can hold any object (note that int is not an object! You'll have to wrap your integers in NSNumber.) Quick example:
NSMutableArray* someIntegers = [[NSMutableArray alloc] initWithCapacity:1];
[someIntegers addObject:[NSNumber numberWithInt:2]];
//I've added one thing to my array.
[someIntegers addObject:[NSNumber numberWithInt:4]];
//See how I can put more objects in than my capacity allows?
//The array will automatically expand if needed.
//The array now contains 2 (at index 0) and 4 (at index 1)
int secondInteger = [[someIntegers objectAtIndex:1] intValue];
//Retrieving an item. -intValue is needed because I stored it as NSNumber,
//which was necessary, because NSMutableArray holds objects, not primitives.
Well in my book it's ok to use VLAs in Objective-C.
So something like
int foo = 10;
int bar[foo];
is allowed. Of course this is not a dynamic array as in automatically adjusting its size. But if you only need a native array on the stack that's fine.
You can use Objetive-C++.
First rename your class like this: MyClass.mm the ".mm" extension tells Xcode that this clas is a Objetive-C++ class, not a Objetive-C class.
then you can use dynamics C++ arrays like this:
int *pixels = new int[self.view.size.width];
for (int offset = 0; offset = self.view.size.width; offset++) {
pixeles[offset] = rawData[offset];
}
then you can pass "pixels" in a method:
Scan *myScan = [[Scan alloc] initWhithArray:pixels];
the method "initWithScan" is declared like this:
-(id)initWithArray:int[]pixels;
the "initWithScan" implementation is like this:
-(id)initWithScan:int[]pixels {
if (self = [super init]) {
for (int i = 0; i < self.myView.size.width; i++) {
NSLog(#"Pixel: %i", pixels[i];
}
}
return self;
}
I hoppe this was useful.

Multidimensional arrays - what's the most convenient way to work with them in Objective-C?

I'm a beginner in Objective-C and I'm trying to find the most convenient way to work with multidimensional arrays in Objective-C. Either I am missing something or they are very ugly to work with.
Let's say we have a classic problem:
read input from file; on the first line, separated by space(" ") are the width and height of the matrix (eg: 3 4)
on the following lines there is the content described by the values above
Eg:
3 4
a b c d
e f g h
i j k l
The first solution I thought of was:
NSMutableArray *matrix = [[NSMutableArray alloc] initWithCapacity: x]; //x = 3 in this specific case
NSMutableArray *cell;
for(cell in matrix)
{
cell = [NSMutableArray initWithCapacity: y];
for(int i = 0; i < y; i++) // y = 4
{
//object is a NSString containing the char[i][j] read from the file
[cell insertObject:object atIndex: i];
}
}
This was the first thing I had in mind when thinking about how I should get my values read from file in a multidimensional array. I know you can use C arrays, but since I will store NSObjects in it, I don't think is such a great idea. Nonetheless, from my point of view is easy to work with C arrays rather the solution I got with Objective-C.
Is there another way you could build a multidimensional array in obj-c and easier than the one above?
How about looping them?
I know I can do something like
NSArray *myArray;
for(int i=0; i < [array count]; i++)
{
[myArray arrayWithArray: [array objectAtIndex: i]];
for(int j=0; j < [myArray count]; j++)
{
NSLog(#"array cell [%d,%d]: %s", i, i, [myArray objectAtIndex: j]);
}
}
But that is still more complicated than your average C multidimensional array loop.
Any thoughts on this?
Objective-C is a superset of C, if you want to work with multidimensional arrays like you would in C, do it that way. If you want to work with objects doing it the Cocoa way, then that's fine too, but you will write more code to do it.
Can you not simply make an array of id?
#import <Foundation/Foundation.h>
int main(int argc, char **argv) {
id ptr[3][4];
NSObject *p;
ptr[0][0] = p;
}
You can do nothing more with NSArray or NSMutableArray in this regard. That is there is nothing like objectAtIndex:i :j
You can always create one-dimensional arrays of the size width * height instead:
const int size = width*height;
NSMutableArray *array = [NSMutableArray arrayWithCapacity:size];
for (int i=0; i<size; ++i) {
NSString *string = [NSString stringWithFormat:#"col=%d, row=%d", i%width, i/width];
[array insertObject:string atIndex:i];
}
Nobody uses direct multi-dimensional arrays of any size in any computer language (except for homework). They simply use too much memory and are therefore too slow. Objective-C is an object-oriented language. Build a class that does what you need.