2013-06-25 41 views
0

我学习这个波阵面OBJ装载机例如:https://github.com/jlamarche/iOS-OpenGLES-Stuff/tree/master/Wavefront%20OBJ%20Loader编码/解码结构对象

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

这一切都工作,但问题是 - 它不是我希望的那样快。

其中一个原因 - 因为在那个例子中使用了struct对象。

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

例如,有结构:

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

这工作,但我有几个结构数组,并在情况下数组都是大 - 这将成为一个大问题。

编辑:

使用阿明Negm - 阿瓦德提供的答案:

如果我简单地改变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:

使用更新的答案,阿明Negm - 阿瓦德提供,

我是能够成功地结构对象存储为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

你要编码的单一结构或结构的数组? “不工作”是什么意思? –

+0

数组结构。不工作 - 因为 - 如果成功编码,则在解码时是随机不正确的值。 –

回答

1

首先:如果数组的长度是可变的,那么根本不可能使用NSValue。这是documented

The type you specify must be of constant length. You cannot store C strings, variable-length arrays and structures, and other data types of indeterminate length in an NSValue—you should use NSString or NSData objects for these types.

所以你应该真的考虑到使用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++) 
+0

这显示了我“使用未声明的标识符的‘NSArchiver’” 它不具有的NSKeyedArchiver工作(表演 - - [的NSKeyedArchiver encodeValueOfObjCType:在:]:数组数丢失或零') 我读了NSArchiver比NSKeyedArchiver旧,所以 - 有可能sdk 4.6(iOS6.1)不再支持它吗? –

+0

哦,对不起,我在Mac OS上测试了这个代码。但是,如何对它进行编码/解码并不重要。这只是测试代码(可能你的实例在对象图中很深,所以你的代码看起来不一样)。只需将NSArchiver更改为NSKeyedArchiver并将NSUnarchiver更改为NSKeyedUnarchiver。但这并不重要。重要的是,*参数valueWithBytes:*没有额外的间接*。查看评论后面的行:“将其封装在一个值中”。 –

+0

请查看我更新的问题。 –