Convert NSValue to NSData and back again, with the correct type

519 views Asked by At

I would like to be able to convert an objective-c object, such as an NSArray or UIImage into an NSData object, which I can then use to write to disk. I first converted them to an NSValue, which I then planned on converting to NSData. This question provided part of the answer, but as they were working with NSNumber, they didn't really have a need to convert it back to NSValue.

I have seen other questions such as this one that relies on NSKeyedArchiver, but I would like to steer away from this due to the vast size inflation that occurs.

Therefore my code at the moment for encoding an NSData object from an NSValue, from the first question, is as follows:

+(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;
}

My question is how would I go about decoding an NSData object that has been encoded in this manner and get back the original objCType from the NSValue?

I would assume I would be using something along these lines

[NSValue valueWithBytes:[data bytes] objCType:typeHere];

How would I get back the type information?

2

There are 2 answers

0
zaph On BEST ANSWER

Use NSKeyedArchiver to save the items and NSKeyedUnarchiver to restore the object. The object must conform to NSCoding and in the case of a collection all contained items must also conform to NSCoding.

See the Apple documentation of NSKeyedArchiver and NSCoder

0
Sven On

Your approach will only work for primitive types (int, float, structs without pointers, ...) inside your NSValue. Otherwise you will only get the meaningless pointer value but not the actual data in your NSData object.

To also pass the actual type string along you would have to figure out a way to get this inside your NSData object as well. Not impossible, but it will not solve your actual problem.

Using a keyed archiver as zaph suggests is much better.