Working With Binary Data

This article contains code examples of common tasks that apply to both immutable and mutable data objects, NSData and NSMutableData objects. Because of the nature of class clusters in Foundation, data objects are not actual instances of the NSData or NSMutableData classes but instead are instances of one of their private subclasses. Although a data object’s class is private, its interface is public, as declared by these abstract superclasses, NSData and NSMutableData.

Creating Data Objects From Raw Bytes

Generally, you create a data object from raw bytes using one of the data... class messages to either the NSData or NSMutableData class object. These methods return a data object containing the bytes you specify.

Typically, the creation methods (such as dataWithBytes:length:) make a copy of the bytes you pass as an argument. In this case, the copied bytes are owned by the data object and are freed when the data object is released. It is your responsibility to free the original bytes.

However, if you create an NSData object with one of the methods whose name includes NoCopy (such as dataWithBytesNoCopy:length:), the bytes are not copied. Instead, the data object takes ownership of the bytes passed in as an argument and frees them when the object is released. (NSMutableData responds to these methods, too, but the bytes are copied anyway and the buffer is freed immediately.) For this reason, the bytes you pass to the NoCopy methods must have been allocated using malloc.

If you prefer that the bytes not be copied or freed when the object is released, you can use the dataWithBytesNoCopy:length:freeWhenDone: or initWithBytesNoCopy:length:freeWhenDone: methods passing NO as the freeWhenDone: argument.

Creating Data Objects From Files or URLs

You use the dataWithContentsOfFile: or dataWithContentsOfURL: class methods to create a data object containing the contents of a file or URL. The following code example creates a data object, myData, initialized with the contents of myFile.txt. The path must be absolute.

NSString *thePath = @"/u/smith/myFile.txt";
NSData *myData = [NSData dataWithContentsOfFile:thePath];

Accessing and Comparing Bytes

The two NSData primitive methods—bytes and length—provide the basis for all other methods in the class. The bytes method returns a pointer to the bytes contained in the data object. The length method returns the number of bytes contained in the data object.

NSData provides access methods for copying bytes from a data object into a specified buffer. The getBytes:length: method copies bytes into a buffer. For example, the following code fragment initializes a data object, myData, with the string myString. It then uses getBytes:length: to copy the contents of myData into aBuffer.

unsigned char aBuffer[20];
NSString *myString = @"Test string.";
const char *utfString = [myString UTF8String];
NSData *myData = [NSData dataWithBytes: utfString length: strlen(utfString)];
[myData getBytes:aBuffer length:20];

The getBytes:range: method copies a range of bytes from a starting point within the bytes themselves.

To extract a data object that contains a subset of the bytes in another data object, use the subdataWithRange: method. For example, the following code fragment initializes a data object, data2, to contain a subrange of data1:

NSString *myString = @"ABCDEFG";
const char *utfString = [myString UTF8String];
NSRange range = {2, 4};
NSData *data1, *data2;
data1 = [NSData dataWithBytes:utfString length:strlen(utfString)];
data2 = [data1 subdataWithRange:range];

To determine if two data objects are equal, use the isEqualToData: method, which does a byte-for-byte comparison.

Copying Data Objects

You can copy data objects to create a read-only copy or to create a mutable copy. NSData and NSMutableData adopt the NSCopying and NSMutableCopying protocols, making it convenient to convert between efficient, read-only data objects and mutable data objects. You use copy to create a read-only copy, and mutableCopy to create a mutable copy.

Saving Data Objects

You can save data objects to a local file or to the internet. The writeToFile:atomically: and writeToURL:atomically: methods let you write the contents of a data object to a local file.