Reputation: 2631
I'm trying to sync objects over GameCenter, accessing their values with KVC on both sides. Setting numeric values using setValue:forKey:
requires them to be NSNumber
objects.
NSValue initWithBytes:objCType:
gives me NSValue
objects even passing encodings for int, float and such.
Do you guys have a better solution instead of checking the encoding manually?
- (NSValue*)smartValueWithBytes:(void*)value objCType:(const char*)type
{
if (0 == strcmp(type, @encode(int)))
{
int tmp;
memcpy(&tmp, value, sizeof(tmp));
return [NSNumber numberWithInt:tmp];
}
if (0 == strcmp(type, @encode(BOOL)))
{
BOOL tmp;
memcpy(&tmp, value, sizeof(tmp));
return [NSNumber numberWithBool:tmp];
}
//etc...
return [NSValue valueWithBytes:value objCType:type];
}
If this is the way to go, is NSNumber
the only NSValue
subclass i need to take care of for KVC?
Upvotes: 2
Views: 3220
Reputation: 55583
Here is my solution to the problem, only has specialization for floating-point values (seeing as they are weird!)
NSValue *safeValueForKVC(const void *input, const char *type)
{
const char numericEncodings[] = {
'c',
'i',
's',
'l',
'q',
'C',
'I',
'S',
'L',
'Q',
'f',
'd',
};
const size_t sizeEncodings[] = {
sizeof(char),
sizeof(int),
sizeof(short),
sizeof(long),
sizeof(long long),
sizeof(unsigned char),
sizeof(unsigned int),
sizeof(unsigned short),
sizeof(unsigned long),
sizeof(unsigned long long),
sizeof(float),
sizeof(double),
};
int typeLen = strlen(type);
if (typeLen == 1)
{
for (int i = 0; i < sizeof(numericEncodings); i++)
{
if (type[0] == numericEncodings[i])
{
// we have a numeric type, now do something with it
if (i == 10)
{
// floating-point value
float fValue = 0;
memcpy(&fValue, input, sizeEncodings[i]);
return [NSNumber numberWithFloat:fValue];
}
if (i == 11)
{
// double value
double dValue = 0;
memcpy(&dValue, input, sizeEncodings[i]);
return [NSNumber numberWithDouble:dValue];
}
// standard numeric value, simply padding with false bits should work for any reasonable integer represetntation
long long value = 0;
memcpy(&value, input, sizeEncodings[i]);
return [NSNumber numberWithLongLong:value];
}
}
}
return [[NSValue alloc] initWithBytes:input objCType:type];
}
Upvotes: 2