Search code examples
objective-cpointersnsvalue

Get buffer pointer from `NSValue`


I'd like to get a pointer to the object stored in an NSValue so that I can modify it. The gist being like this:

// Get a pointer to the value's buffer (it'd be void*, I guess).
CGRect *myRect = [rectValue getPointer];

// Modify the rectangle.
myRect->origin = CGPointMake(10, 10);

I notice NSValue has the method pointerValue, but the documentation says:

The value as a pointer to void. If the value object was not created to hold a pointer-sized data item, the result is undefined.

… so this only seems to be suitable for values that are pointers, which this isn't, it's a CGRect.

Incidentally, if the answer is "you can't do this", that still a good answer as far as I'm concerned :-) An explanation of why not would be interesting, as it seems like an amazingly obvious absence in the API.


Solution

  • I believe the answer is indeed, "you can't do this."*

    Here are a few reasons that come to mind as to why this should be the case.

    • NSValue, like many core data types in Objective-C, is immutable. Allowing you to grab a pointer to the internal value stored within the instance would not be very good for its immutability.
    • Access to such a pointer would inevitably have to return a void *. This circumvents all of the compiler's ability to type-check, which is there for your own good!
    • In general, classes try to hide as much of their internal state and functionality away from the outside world as possible, and manage interaction with that outside world carefully. Imagine the silly case of an NSValue instance wanting to be aware of each time you access its stored value as a CGRect (as far as I know, NSValue does not actually monitor this). With a pointer, it could not know when you do so. With the method -[NSValue CGRectValue], however, you have no choice but to inform it.

    Faced especially with those first two reasons, you might even say to yourself, well if all that's true, why does pointerValue exist? This does potentially allow mutability, and it does potentially allow pointers to not be type-checked. Good question, but easily answered: if you create an NSValue instance with a pointer – say, with +[NSValue valueWithPointer:], the only option for getting that pointer back out of the instance is a method that returns void *. Anything else would constitute some sort of assumption on the part of the method

    * "Can't" is a relative term here. For example, valueForKey: might still work if you knew the internal key name.