Storing a struct in an NSArray
Back with my daily silly question. Today I'm trying to put a struct in an NSArray. Alright, that's easy, wrap it in a NSData. If you know me, you know you're about to see code. In this example, I'm loading a vertex line from a Wavefront OBJ into a struct and sticking it in an array.
NSArray *verticeLineParts = [currentLine componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
Coordinate c = CoordinateMake([[verticeLineParts objectAtIndex:1] floatValue],
[[verticeLineParts objectAtIndex:2] floatValue],
[[verticeLineParts objectAtIndex:3] floatValue]);
[vertices addObje开发者_StackOverflow社区ct:[[NSData alloc] initWithBytes:&c length:sizeof(c)]];
This seems to work fine. The first few objects in the output:
2010-10-18 14:18:08.237 ObjLoader[3778:207] (
<5d1613bd 13f3da3f 8ac745bd>,
<f04c28bd 13f3da3f d88048bd>,
<649427bd d61ddb3f d88048bd>,
<477625bd d845db3f d88048bd>,
<4c1722bd 1668db3f d88048bd>,
When it comes to printing them out after pulling them from the array, not so much. The offending code:
for (int i = 0; i < [vertices count]; i++) {
Coordinate c;
fillCoordinateFromData(c, [vertices objectAtIndex:i]);
NSLog(@"%@", CoordinateToNSString(c));
}
[snip]
void fillCoordinateFromData(Coordinate c, NSData *d) {
void *bytes = malloc(12);
[d getBytes:bytes];
memcpy((void *)&c, &bytes, 12);
free(bytes);
}
Of course, the offending output:
2010-10-18 14:22:00.692 ObjLoader[3825:207] 9.885923, -6.837428, 0.000000
2010-10-18 14:22:00.693 ObjLoader[3825:207] 9.885923, -6.837428, 0.000000
2010-10-18 14:22:00.694 ObjLoader[3825:207] 9.885923, -6.837428, 0.000000
2010-10-18 14:22:00.695 ObjLoader[3825:207] 9.885923, -6.837428, 0.000000
2010-10-18 14:22:00.695 ObjLoader[3825:207] 9.885923, -6.837428, 0.000000
I think this is caused by C wizardry attempted by someone who's not a C wizard, kind of like The Sorcerer's Apprentice. I think this should be obvious to a wizard of the 99th degree, or if someone can suggest a more modern way to do this, let me know.
Thanks, Will
void fillCoordinateFromData(Coordinate c, NSData *d) {
This passes c
by value. The modification of c
in this function won't be reflected back to the caller.
You need to pass by pointer (reference) instead.
fillCoordinateFromData(&c, [vertices objectAtIndex:i]);
void fillCoordinateFromData(Coordinate* pc, NSData *d) {
void *bytes = malloc(12);
[d getBytes:bytes];
memcpy((void *)c, &bytes, 12);
free(bytes);
}
but it is better to just return the Coordinate.
Coordinate c = getCoordinateFromData([vertices objectAtIndex:i]);
Coordinate getCoordinateFromData(NSData* d) {
Coordinate c;
[d getBytes:&c]; // and let's not waste time allocating 12 bytes.
return c;
}
BTW, by convention structs are wrapped in NSValue, not NSData.
[vertices addObject:[NSValue valueWithBytes:&c withObjCType:@encode(Coordinate)]];
Coordinate getCoordinateFromData(NSValue* d) {
Coordinate c;
[d getValue:&c];
return c;
}
精彩评论