NSValue
As part of playing the role of Abraham Lincoln in the eponymous 2012 biopic, Daniel Day-Lewis would insist on walking through a refrigerator box marked “TIME MACHINE” anytime he entered or left the set. True Story.
While the ends certainly justify the means when it comes to Mr. Day-Lewis’ method acting, one can’t help but marvel at the absurdity of a magical cardboard box used as a nexus between the modern and historical worlds.
Yet, this is exactly what we do as Objective-C programmers.
…well not exactly, but there is a box involved.
As mentioned time and again in NSHipster, what makes Objective-C such a curiosity is the way it merges the old, procedural world of C with the modern Object-Oriented influences of Smalltalk. When done correctly, this tension can be exploited to craft semantically rich software without sacrificing performance. But bridging that gap between old and new is a miasma of casts, bridges, and of course, boxes.
Boxing is the process of encapsulating scalars (int
, double
, BOOL
, etc.) and value types (struct
, enum
) with an object container, and is primarily used to store those values in collection objects—namely arrays and dictionaries.
NSNumber
is often used to box scalars, but in Foundation, the reigning featherweight champion of boxing is NSValue
.
NSValue
is a simple container for a single C or Objective-C data value. It can hold scalars and value types, as well as pointers and object IDs.
While boxing is an admittedly dry subject matter, there are two methods in particular that are worth noting: +value
, which serves as a primer for working with NSValue
, and
+value
, which is surprisingly useful for being relatively unknown.
value With Bytes:obj CType:
+value
Creates and returns an NSValue object that contains a given value, which is interpreted as being of a given Objective-C type.With Bytes:obj CType:
value
: The value for the newNSValue
object.type
: The Objective-C type of value.type
should be created with the Objective-C@encode()
compiler directive; it should not be hard-coded as a C string.
@encode
was discussed in our rundown of the myriad @
Compiler Directives:
@encode()
: Returns the type encoding of a type. This type value can be used as the first argument encode inNSCoder -encode
.Value Of Obj CType:at
The subject of type encodings would make for a great article of its own, but the main takeaway is that it serves as a terse, human-readable representation of the structure of a type. For example,
typedef struct example {
id an Object;
char *a String;
int an Int;
} Example;
…has the encoding:
{example=@*i}
NSValue
uses this type encoding to create the necessary data structures to represent these values internally. Neat!
value With Nonretained Object:
+value
Creates and returns an NSValue object that contains a given object.With Nonretained Object:
an
: The value for the new object.Object
If you already knew about value
, you should be nodding with a knowing grin. If you didn’t, you’re likely staring incredulously with mouth agape. Or if not, you will be soon.
In short, value
allows objects to be added to a collection, without the need for satisfying <NSCopying>
.
It’s something that comes up occasionally, working with objects that can’t be directly added to an NSArray
or NSDictionary
. Without knowing about value
, this would be something that would throw off your entire game—especially if you’re just starting out in Objective-C.
But now you’re in the know. You won’t be stifled by such pedestrian concerns. You need not grope around for answers with NSPointer
or NSMap
. Today is a new day.
Having unpacked all of this wisdom about NSValue
, you can now face that cruel divide between procedural and object-oriented; C and Smalltalk. Because everything is easy with a magic box.