NSData getBytes随机返回垃圾

时间:2014-08-05 14:38:32

标签: ios objective-c nsdata

我正在尝试在iOS应用中保存并加载自定义文件格式。格式存储各种数据,但其中包括用户为地图输入的名称。我随机发现,因为我正在尝试读取这个地图名称(在文件中存储为char),我的NSData对象将读取垃圾。以下是我读取地图名称的代码(start已设置为正确的起始位置):

NSData* data = ....;
uint mapNameLength;
char* mapNameChar;
NSString* mapNameString;

[data getBytes:&mapNameLength range:NSMakeRange(start, 4)];
start += 4;
mapNameChar = (char *)malloc(sizeof(char) * mapNameLength);
[data getBytes:mapNameChar range:NSMakeRange(start, mapNameLength)];
mapNameString = [NSString stringWithUTF8String:mapNameChar];

NSLog(@"mapNameLength: %u, mapNameChar: %s, Map name string: %@", mapNameLength, mapNameChar, mapNameString);

正如您所看到的,我正在读取名称的长度,然后读取许多char值,然后将其转换为NSString。这是NSLog工作时的输出(我只是敲了一下键盘来制作一个长名字):

mapNameLength: 49, mapNameChar: kandfianeifniwbvuandivbwirngiwnrivnwrivnwidnviwdv, Map name string: kandfianeifniwbvuandivbwirngiwnrivnwrivnwidnviwdv

以下是NSLog不起作用时的输出:

mapNameLength: 49, mapNameChar: kandfianeifniwbvuandivbwirngiwnrivnwrivnwidnviwdvfi?p?, Map name string: (null)

那些“?”实际上是这里没有显示的特殊字符,所以我添加了它们。第一个是“ETX”,第二个是Sublime Text中的“SOH”。

要创建文件,这就是我正在做的事情:

NSString* mapName = ....;
uint mapNameLength = (uint)mapName.length;
NSMutableData* data = ....;
//...
//Write file type and version here
//...
[data appendBytes:&mapNameLength length:4];
[data appendData:[mapName dataUsingEncoding:NSUTF8StringEncoding]];
//...
//Write other stuff
//...

NSString* path = [FileManager applicationDocumentsDirectory];
path = [path stringByAppendingFormat:@"/%@", fileName];
BOOL success = [data writeToFile:path options:NSDataWritingAtomic error:&error];

我只写了一次文件,所以我知道数据总是一样的。那么,为什么我的数据对象有时会从中获取随机字节?

1 个答案:

答案 0 :(得分:2)

我不确定,但我不认为您正在存储终止NUL字符,因此您需要在读取字符串后添加一个缓冲区:

mapNameChar = (char *)malloc(sizeof(char) * (mapNameLength + 1));   // Add +1
[data getBytes:mapNameChar range:NSMakeRange(start, mapNameLength)];
mapNameChar[mapNameLength] = '\0';            // Terminate with NUL
mapNameString = [NSString stringWithUTF8String:mapNameChar];

最好还是忘记malloc()和C-String并直接从NSString对象创建NSData

mapNameString = [[NSString alloc] initWithBytes:(const char *)([data bytes]) + start
                                         length:mapNameLength
                                       encoding:NSUTF8StringEncoding];