0

我正在研究这个波前 obj 加载器示例:https ://github.com/jlamarche/iOS-OpenGLES-Stuff/tree/master/Wavefront%20OBJ%20Loader

为了提高对象加载速度——我决定将加载的对象编码为 NSValue,然后存储在核心数据中。稍后,当需要再次显示相应的对象时 - 我从数据库中获取必要的 nsvalue 并取消归档它。

一切正常,但问题是 - 它没有我希望的那么快。

原因之一 - 因为在该示例中使用了 struct 对象。

我没有成功对它们进行编码/解码,所以我使用了 NSMutableArray,我在其中写入了所有结构数据,然后 - 我遍历它以将值放回结构对象。

例如,有结构:

typedef struct {
GLfloat x;
GLfloat y;
GLfloat z;
} Vertex3D;

然后定义:

typedef Vertex3D Vector3D;

但在 OpenGLWaveFrontObject 类中,它是这样使用的:

Vector3D *vertexNormals;    

我怎样才能像这样编码/解码结构?

我试过这样:

[coder encodeObject:[NSValue value:&vertexNormals withObjCType:@encode(Vector3D)] forKey:@"vertexNormals"];

或像这样:

[coder encodeObject:[NSValue value:&vertexNormals withObjCType:@encode(Vector3D[30])] forKey:@"vertexNormals"];

但它不起作用 - 如果成功编码,那么在解码时 - 值不正确。

例如,我如何放回结构必要值的数组:

    vertices = malloc(sizeof(Vertex3D) *  [verticesArray count]);

    for(int i = 0; i < [verticesArray count]; i++)
    {            
        vertices[i].x = [[[verticesArray objectAtIndex:i] objectAtIndex:0] floatValue];

        vertices[i].y = [[[verticesArray objectAtIndex:i] objectAtIndex:1] floatValue];

        vertices[i].z = [[[verticesArray objectAtIndex:i] objectAtIndex:2] floatValue];
    }

这行得通,但我有更多的结构数组,如果数组很大 - 这将成为一个大问题。

编辑:

使用Amin Negm-Awad提供的答案:

如果我只是将 NSArchiver 更改为 NSKeyedArchiver - 它会引发错误:

[NSKeyedArchiver encodeArrayOfObjCType:count:at:]: unsupported type "{?=fff}]" for array encoding' 

当我尝试:

NSValue *encapsulated = [NSValue valueWithBytes:vertexNormals objCType:@encode(Vertex3D[3])]; 
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:encapsulated]; 
[coder encodeObject:data forKey:@"vertexNormals"]; 

并创建了 vertexNormals:

vertexNormals = calloc(3, sizeof(Vector3D)); 

并填写了您提供的类似数据。

编辑2:

使用 Amin Negm-Awad 提供的更新答案,

我成功地将结构对象存储为 NSData 并对其进行编码,然后对其进行解码。有用!

例如,这样它也可以帮助其他人:

//Encode
NSData *verticesData = [NSData dataWithBytes:vertices length:numberOfVertices * sizeof(Vector3D)];

[coder encodeObject:verticesData forKey:@"vertices"];


//Decode
vertices = malloc(sizeof(Vertex3D) * numberOfVertices);

NSData *verticesData = [decoder decodeObjectForKey:@"vertices"];

[verticesData getBytes:vertices length:sizeof(Vertex3D) *  numberOfVertices];

其中 Vertex3D 是一个结构:

typedef struct {
GLfloat x;
GLfloat y;
GLfloat z;
} Vertex3D;

并用作结构数组(我不知道它是如何真正调用的):

Vertex3D *vertices;

不幸的是,我无法存储纹理数据。我可以编码和解码,但解码后的数据总是随机离奇。

我以这种方式声明它:

GLfloat *textureCoords;

我以这种方式编码/解码:

//Encode
NSData *textureCoordsData = [NSData dataWithBytes:textureCoords length:valuesPerCoord * numberOfVertices];

[coder encodeObject:textureCoordsData forKey:@"textureCoords"];

//Decode
textureCoords = malloc(sizeof(GLfloat) * valuesPerCoord * numberOfVertices);

NSData *textureCoordsData = [decoder decodeObjectForKey:@"textureCoords"];

[textureCoordsData getBytes:textureCoords length:valuesPerCoord * numberOfVertices];

可能是什么问题呢?

4

1 回答 1

1

首先:如果数组是可变长度的,根本不可能使用 NSValue。这是记录在案的:

您指定的类型必须是恒定长度。您不能在 NSValue 中存储 C 字符串、可变长度数组和结构以及其他不确定长度的数据类型——您应该为这些类型使用 NSString 或 NSData 对象。

因此,您应该真正考虑改用 NSData 。

但是,如果你想使用 NSValue (因为你有一个恒定长度的数组):

您的两种方法都有一个额外的间接性。第一个也有错误的类型。什么应该起作用:

// Create some data
Vertex3D *cArray = malloc(30 * sizeof(Vertex3D));
NSInteger i;
for (i=0; i<30; i++)
{
   cArray[i].x = i;
   cArray[i].y = 9811;
   cArray[i].z = 29-i;
}
NSLog(@"%p", cArray);

// Encapsulate that in a value
// Have a look at the parameters
NSValue *encapsulated = [NSValue valueWithBytes:cArray objCType:@encode(Vertex3D[30])];

// Put it through a coder and store the coded data on disk
NSData *data = [NSArchiver archivedDataWithRootObject:encapsulated];
[data writeToFile:[@"~/Desktop/valueTest" stringByExpandingTildeInPath] atomically:YES];
// Out is done here

// from disk
data = [NSData dataWithContentsOfFile:[@"~/Desktop/valueTest" stringByExpandingTildeInPath]];
encapsulated = [NSUnarchiver unarchiveObjectWithData:data];

Vertex3D *cArray2 = malloc(30 * sizeof(Vertex3D));
[encapsulated getValue:cArray2];
for (i=0; i<30; i++)
{
   NSLog(@"%f %f %f", cArray[i].x, cArray[i].y, cArray[i].z);
}
NSLog(@"%p", cArray2);

这适用于我的测试代码

由于键控实现的问题而更新:要将 c 数组存储在 NSData 实例而不是 NSValue 实例中,请改为执行此操作

NSLog(@"%p", cArray);

将代码更改为

// Convert to an NSData instance
NSData *data = [NSData dataWithBytes:cArray length:lengthInBytes];
[data writeToFile:[@"~/Desktop/valueTest" stringByExpandingTildeInPath] atomically:YES];
// Out is done here

// from disk
data = [NSData dataWithContentsOfFile:[@"~/Desktop/valueTest" stringByExpandingTildeInPath]];
Vertex3D *cArray2 = malloc(lengthInBytes);
[data getBytes:cArray2 length:lengthInBytes];

直到

for (i=0; i<30; i++)
于 2013-06-26T04:41:13.617 回答