2

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.

Benjohn
  • 13,228
  • 9
  • 65
  • 127

1 Answers1

1

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.

ravron
  • 11,014
  • 2
  • 39
  • 66
  • Thanks for the answer – I'm glad I'm not missing something, but I'm not sure I really agree with your first two points! :-) So, there could be a mutable variant (like many core types), or a pointer to const void could be returned. The set up of `NSValue` already assumes you're getting the type right when you instantiate. In this case the type you're expecting could be specified so `NSValue` can check that's what it has? But … I think you last point is sound – `NSNumber`s perform coercion between types, which a void pointer doesn't do at all. Perhaps `NSData` could an alternative? – Benjohn Dec 05 '14 at 23:19
  • Great points, @Benjohn. I would say that a mutable variant of `NSValue` would not be a very valuable addition, because that class is just a thin object wrapper for a single piece of – typically – C-style data. Being able to mutate that data just would not be that useful, and would come at the cost of the possible increases in complexity and opportunities for bugs (e.g., being passed an `NSMutableValue` which you think is immutable, but then changes out from under you). Plus, creating new `NSValue`s is very low-overhead, so there's little advantage cutting that out. – ravron Dec 06 '14 at 00:51
  • Heh – it interesting that in this case I didn't care about the run time overhead. It was the code overhead I was bothered about – unwrapping, updating the size, and rewrapping again, v, setting the size property of the structure with a pointer dereference. Perhaps it's a class I should build :-) – Benjohn Dec 06 '14 at 20:22