Using Values

An NSValue object is a simple container for a single C or Objective-C data item. It can hold any of the scalar types such as int, float, and char, as well as pointers, structures, and object ids. The purpose of this class is to allow items of such data types to be added to collection objects such as instances of NSArray or NSSet, which require their elements to be objects. NSValue objects are always immutable.

To create an NSValue object with a particular data item, you provide a pointer to the item along with a C string describing the item’s type in Objective-C type encoding. You get this string using the @encode() compiler directive, which returns the platform-specific encoding for the given type (see “Type Encodings” for more information about @encode() and a list of type codes). For example, this code excerpt creates theValue containing an NSRange:

NSRange myRange = {4, 10};
NSValue *theValue = [NSValue valueWithBytes:&myRange objCType:@encode(NSRange)];

The following example illustrates encoding a custom C structure.

// assume ImaginaryNumber defined:
typedef struct {
    float real;
    float imaginary;
} ImaginaryNumber;
 
 
ImaginaryNumber miNumber;
miNumber.real = 1.1;
miNumber.imaginary = 1.41;
 
NSValue *miValue = [NSValue valueWithBytes: &miNumber
                            withObjCType:@encode(ImaginaryNumber)];
 
ImaginaryNumber miNumber2;
[miValue getValue:&miNumber2];

The type you specify must be of constant length. You cannot store C strings, variable-length arrays and structures, and other data types of indeterminate length in an NSValue—you should use NSString or NSData objects for these types. You can store a pointer to variable-length item in an NSValue object. The following code excerpt incorrectly attempts to place a C string directly into an NSValue object:

/* INCORRECT! */
char *myCString = "This is a string.";
NSValue *theValue = [NSValue valueWithBytes:myCString withObjCType:@encode(char *)];

In this code excerpt the contents of myCString are interpreted as a pointer to a char, so the first four bytes contained in the string are treated as a pointer (the actual number of bytes used may vary with the hardware architecture). That is, the sequence “This” is interpreted as a pointer value, which is unlikely to be a legal address. The correct way to store such a data item is to use an NSString object (if you need to contain the characters in an object), or to pass the address of its pointer, not the pointer itself:

/* Correct. */
char *myCString = "This is a string.";
NSValue *theValue = [NSValue valueWithBytes:&myCString withObjCType:@encode(char **)];

Here the address of myCString is passed (&myCString), so the address of the first character of the string is stored in theValue.