Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why can't we store C struct directly in NSArray

Tags:

c

objective-c

I ran into an error when I was trying to store a C struct into a NSArray (I was able to solve it by converting into NSData as specified in the link below). However, I am curious to understand why it did not work without all this hassle of using NSData. link to solution I used

Please note: I don't want a solution, it is already solved. I am just trying to improve my understanding of the fundamentals of Objective-C by understanding why the direct approach below did not work.

What I was trying to do: A simple program that allows a person to add a grocery item and mark it as done after adding to shopping cart

  1. Define C struct with 3 elements (name of item, count and BOOL to keep track of whether it has been added to cart or not)

  2. Each time a new item is created I do the following groceryItem *secondGroceryItem = malloc(sizeof(groceryItem)) ; secondGroceryItem->itemName="Beer" ; secondGroceryItem->count = 3 ; secondGroceryItem->purchased=NO ;

  3. Then I add it to a NSMutableArray keeping track of grocery items using [myGroceryList addObject:(__bridge id)(secondGroceryItem)]

where myGroceryList is defined earlier as NSMutableArray *myGroceryList = [NSMutableArray array] ;

This does not work. I had to convert into a NSData before storing in NSMutableArray. Why can't I just store a pointer to my C struct directly in the NSMutableArray?

like image 728
Smart Home Avatar asked Mar 03 '26 18:03

Smart Home


2 Answers

It should be noted that the reason we can't put C-structs into NSArray isn't because of anything special about structs. Instead, we should consider NSArray to be a special type of array.

We can put structs in arrays in Objective-C. We know this because C programmers put structs in arrays.

NSArray (and NSMutableArray and all the other NS collection objects) is a special class designed to implement the array data structure specifically for Objective-C objects. The fact that NSArray only allows Objective-C objects allows NSArray to do things like makeObjectsPerformSelector:. We're sending an Objective-C message to everything in the array. We couldn't allow this if we allowed non-Objective-C-objects into the array.

It's not just structs that aren't allowed into NSArray. All the primitive data types are not allowed in an NSArray. This even includes NSInteger and CGFloat, because remember, these are typedef'd primitives--not objects.

It should be noted however, that NSArray is not the only array-like data structure available to us in Objective-C. Remember, Objective-C is a strict superset of C. And as I already mentioned, C programmers are already putting structs into an array.

We can always use a C-style array. In fact, although it's very rarely done (because of the power of Objective-C arrays), we can even create a C-style array of Objective-C objects.

Consider:

NSString *stringArray[3];
stringArray[0] = @"foo";
stringArray[1] = @"bar";
stringArray[2] = @"baz";

for (int i = 0; i < 3; ++i) {
    NSLog(@"%@", stringArray[i]);
}

This compiles, runs, and does exactly what you'd expect in Objective-C. As such, we can do exact same with a struct:

typedef struct Foo {
    int x;
    int y;
} Foo;

Foo fooArray[3];
fooArray[0] = (Foo){.x = 1, .y = 2};
fooArray[1] = (Foo){.x = 3, .y = 4};
fooArray[2] = (Foo){.x = 5, .y = 6};

for (int i = 0; i < 3; ++i) {
    NSLog(@"Foo(x: %i, y: %i)", fooArray[i].x, fooArray[i].y);
}

Again, this is perfectly valid Objective-C code.

The question you have to ask yourself: Is it better to have a struct and deal with a C-style array, or would my struct be better as an object that I can put in an NSArray? I wouldn't use a struct that I'm converting to NSData and back just for the sake of putting it into an NSArray...that seems like a mess.

like image 76
nhgrif Avatar answered Mar 05 '26 09:03

nhgrif


An NSArray or NSMutableArray consists of objects. C datatypes are not objects. So you can not store them directly in a NSArray.

I assume that you know how to create an object. Include in this object the variables with the C-datatype.

Once you have that, add that object to the NSArray:

NSMutableArray *yourArray = [[NSMutableArray alloc] init];

YourObject *object1 = [[YourObject alloc] init];
[yourArray addObject: object1];
like image 40
Vincent Avatar answered Mar 05 '26 08:03

Vincent



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!