A有一些NSValue
(通过KVC获得valueForKey
)我需要附加到NSData
对象,以便使用Game Center通过网络发送它。显然,我还需要将NSValue
从NSData
转换回更多KVC(setValue:forKey:
)。
我不知道每个NSValue
的确切类型,因此我仅限于使用NSValue
和NSData
提供的界面。我应该提到NSValue
永远不是指针类型。
我很惊讶没有[NSData dataWithValue:value]
,也没有类似[value dataWithEncoding:]
或类似的东西。但也许我是盲目的,没有看到明显的选择。我想过使用getValue:
将值复制到void*
缓冲区,但除了使用objCType
并将其与所有可能的类型进行比较之外,我应该如何确定缓冲区长度呢? / p>
我应该怎么做?
注意:
NSKeyedArchiver
是不可能的,因为它非常低效。 4字节浮点数归档为142字节NSData
,8字节CGPoint
在归档到NSData
时使用260字节。将发送的数据量保持在最低限度对我正在做的事情至关重要。
答案 0 :(得分:17)
Martin Gordon的答案越来越近了,但幸运的是你不必手动解析objCType字符串。有一个功能可以做到:NSGetSizeAndAlignment。从中你可以得到从getValue:获得的值的大小/长度。 This question引导我找到解决方案。
我最终为NSData创建了一个类别,允许我从NSNumber或NSValue对象创建NSData:
@interface NSData (GameKitCategory)
+(NSData*) dataWithValue:(NSValue*)value;
+(NSData*) dataWithNumber:(NSNumber*)number;
@end
@implementation NSData (GameKitCategory)
+(NSData*) dataWithValue:(NSValue*)value
{
NSUInteger size;
const char* encoding = [value objCType];
NSGetSizeAndAlignment(encoding, &size, NULL);
void* ptr = malloc(size);
[value getValue:ptr];
NSData* data = [NSData dataWithBytes:ptr length:size];
free(ptr);
return data;
}
+(NSData*) dataWithNumber:(NSNumber*)number
{
return [NSData dataWithValue:(NSValue*)number];
}
@end
我还在此NSValue / NSNumber数据之前添加了一个小标题,允许我解码数据的属性以及数据部分中的字节数。有了它,我可以将值恢复到远程属性。
答案 1 :(得分:4)
由于NSValue
采用NSCoding
协议,您可以使用NSCoder
子类,NSKeyedArchiver
和NSKeyedUnarchiver
:
- (NSData *)dataWithValue:(NSValue *)value {
return [NSKeyedArchiver archivedDataWithRootObject:value];
}
- (NSValue *)valueWithData:(NSData *)data {
return (NSValue *)[NSKeyedUnarchiver unarchiveObjectWithData:data];
}
如果无法使用NSKeyedArchiver
和NSKeyedUnarchiver
(针对结果数据大小问题),那么您必须自己查找所包含值的大小:
- (NSData *)dataWithValue:(NSValue *)value {
// Can use NSGetSizeAndAlignment() instead. See LearnCocos2D's answer.
if (type[0] == '{') {
// Use the various NSValue struct value methods to detect the type.
} else if (type[0] == 'c') {
size = sizeof(char);
} else if (type[0] == 'i') {
size = sizeof(int);
} // etc for all/most of the values in the table linked below [1];
void *bytes = malloc(size);
[value getValue:bytes];
return [NSData dataWithBytes:bytes length:size];
}
答案 2 :(得分:0)
您可以使用NSCoder(如NSKeyedArchiver)归档数据,然后发送生成的NSData。另一方面,你可以解开它。如果您在NSValue中包装结构和其他非归档内容,可能会有一些警告(例如http://www.cocoabuilder.com/archive/cocoa/82344-nskeyedarchiver-and-nsvalue.html)。