Reading and Writing Property-List Data

Using Objective-C Methods to Read and Write Property-List Data

You have two major ways to write property-list data to the file system:

The first approach is simpler—it requires only one method invocation instead of two—but the second approach has its advantages. It allows you to convert the runtime property list to binary format as well as an XML property list. When you convert a static representation of a property list back into a graph of objects, it also lets you specify with more flexibility whether those objects are mutable or immutable.

To expand on this last point, consider this example. You have an XML property list whose root object is an NSArray object containing a number of NSDictionary objects. If you load that property list with this call:

NSArray * a = [NSArray arrayWithContentsOfFile:xmlFile];

a is an immutable array with immutable dictionaries in each element. Each key and each value in each dictionary are also immutable.

If you load the property list with this call:

NSMutableArray * ma = [NSMutableArray arrayWithContentsOfFile:xmlFile];

ma is a mutable array with immutable dictionaries in each element. Each key and each value in each dictionary are immutable.

If you need finer-grained control over the mutability of the objects in a property list, use the propertyListFromData:mutabilityOption:format:errorDescription: class method, whose second parameter permits you to specify the mutability of objects at various levels of the aggregate property list. You could specify that all objects are immutable (NSPropertyListImmutable), that only the container (array and dictionary) objects are mutable (NSPropertyListMutableContainers), or that all objects are mutable (NSPropertyListMutableContainersAndLeaves).

For example, you could write code like this:

NSMutableArray *dma = (NSMutableArray *)[NSPropertyListSerialization
                        propertyListFromData:plistData
                        mutabilityOption:NSPropertyListMutableContainersAndLeaves
                        format:&format
                        errorDescription:&error];

This call produces a mutable array with mutable dictionaries in each element. Each key and each value in each dictionary are themselves also mutable.

Using Core Foundation Functions to Read and Write Property-List Data

To write out XML property lists using Property List Services (Core Foundation), call the function the CFURLWriteDataAndPropertiesToResource function, passing the CFData object created through calling CFPropertyListCreateXMLData. To read an XML property list from the file system or URL resource, call the function CFURLCreateDataAndPropertiesFromResource. Then convert the created CFData object to a graph of property-list objects by calling the CFPropertyListCreateFromXMLData function.

Listing 6-1 includes a fragment of the larger code example in “Saving and Restoring a Property List in Core Foundation” that illustrates the use of these functions.

Listing 6-1  Writing and reading property lists using Core Foundation functions

void WriteMyPropertyListToFile( CFPropertyListRef propertyList,
            CFURLRef fileURL ) {
   CFDataRef xmlData;
   Boolean status;
   SInt32 errorCode;
 
   // Convert the property list into XML data.
   xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, propertyList );
 
   // Write the XML data to the file.
   status = CFURLWriteDataAndPropertiesToResource (
               fileURL,                  // URL to use
               xmlData,                  // data to write
               NULL,
               &errorCode);
 
   CFRelease(xmlData);
}
 
CFPropertyListRef CreateMyPropertyListFromFile( CFURLRef fileURL ) {
   CFPropertyListRef propertyList;
   CFStringRef       errorString;
   CFDataRef         resourceData;
   Boolean           status;
   SInt32            errorCode;
 
   // Read the XML file.
   status = CFURLCreateDataAndPropertiesFromResource(
               kCFAllocatorDefault,
               fileURL,
               &resourceData,            // place to put file data
               NULL,
               NULL,
               &errorCode);
 
   // Reconstitute the dictionary using the XML data.
   propertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
               resourceData,
               kCFPropertyListImmutable,
               &errorString);
 
   if (resourceData) {
        CFRelease( resourceData );
    else {
        CFRelease( errorString );
    }
   return propertyList;
}

You may also write and read property lists to the file system using the functions CFPropertyListWriteToStream and CFPropertyListCreateFromStream. These functions require that you open and configure the read and write streams yourself.