我正在研究这个wavefront obj加载器示例:https://github.com/jlamarche/iOS-OpenGLES-Stuff/tree/master/Wavefront%20OBJ%20Loader
为了提高对象加载速度 - 我决定将加载的对象编码为NSValue,然后存储在Core数据中。之后,当需要再次显示相应的对象时 - 我从数据库中获取必要的nsvalue并取消它。
一切正常,但问题是 - 它没有那么快,我希望它会如此。
其中一个原因 - 因为,在该示例中使用了struct对象。
我没有成功对它们进行编码/解码,所以我使用了NSMutableArray,其中我编写了所有结构数据,后来 - 我遍历它以将值放回到struct对象。
例如,有struct:
typedef struct {
GLfloat x;
GLfloat y;
GLfloat z;
} Vertex3D;
然后定义:
typedef Vertex3D Vector3D;
但在OpenGLWaveFrontObject类中,它的使用方式如下:
Vector3D *vertexNormals;
我怎么能像这样编码/解码struct?
我试过这样:
[coder encodeObject:[NSValue value:&vertexNormals withObjCType:@encode(Vector3D)] forKey:@"vertexNormals"];
或者像这样:
[coder encodeObject:[NSValue value:&vertexNormals withObjCType:@encode(Vector3D[30])] forKey:@"vertexNormals"];
但它不起作用 - 如果成功编码,则在解码时 - 值不正确。
示例,我如何放回struct必需值的数组:
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提供的更新答案,
我成功地将struct对象存储为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];
可能是什么问题?
答案 0 :(得分:1)
首先:如果数组具有可变长度,则根本无法使用NSValue。这是documented:
您指定的类型必须是恒定长度。你不能存储C. 字符串,可变长度数组和结构,以及其他数据类型 在NSValue中的不确定长度 - 你应该使用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++)