简体   繁体   中英

why can't we store C struct directly in NSArray

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?

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.

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];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM