2010-10-18 17 views
5

De vuelta con mi pregunta diaria tonta. Hoy estoy tratando de poner una estructura en un NSArray. Muy bien, eso es fácil, envuélvelo en NSData. Si me conoces, sabes que estás a punto de ver el código. En este ejemplo, estoy cargando una línea de vértice desde un Wavefront OBJ en una estructura y pegándola en una matriz.Almacenar una estructura en un NSArray

 NSArray *verticeLineParts = [currentLine componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 
     Coordinate c = CoordinateMake([[verticeLineParts objectAtIndex:1] floatValue], 
             [[verticeLineParts objectAtIndex:2] floatValue], 
             [[verticeLineParts objectAtIndex:3] floatValue]); 
     [vertices addObject:[[NSData alloc] initWithBytes:&c length:sizeof(c)]]; 

Esto parece funcionar bien. Los primeros objetos en la salida:

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>, 

Cuando se trata de imprimir a cabo después de tirar de ellos a partir de la matriz, no tanto. El código erróneo:

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); 
} 

Por supuesto, la salida del infractor:

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 

Creo que esto es causado por la magia C intentado por alguien que no es un mago C, una especie de aprendiz de brujo. Creo que esto debería ser obvio para un mago del grado 99, o si alguien puede sugerir una forma más moderna de hacer esto, házmelo saber.

Gracias, Will

Respuesta

10
void fillCoordinateFromData(Coordinate c, NSData *d) { 

Esto pasa c por valor. La modificación de c en esta función no se reflejará de nuevo a la persona que llama.

En su lugar, debe pasar por el puntero (referencia).

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); 
} 

pero es mejor simplemente devolver el 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, por estructuras de convenciones están envueltos en NSValue, no NSData.

[vertices addObject:[NSValue valueWithBytes:&c withObjCType:@encode(Coordinate)]]; 

Coordinate getCoordinateFromData(NSValue* d) { 
    Coordinate c; 
    [d getValue:&c]; 
    return c; 
} 
Cuestiones relacionadas