Сериализация списка свойств

Используя NSPropertyListSerialization класс или Property List Services (Базовая Основа), можно сериализировать списки свойств в их (объектной) форме во время выполнения к статическому представлению, которое может быть сохранено в файловой системе; позже можно десериализовать то статическое представление назад в исходные объекты списка свойств. Сериализация списка свойств автоматически принимает во внимание порядок байтов на различных архитектурах процессора — например, можно правильно считать на основанном на Intel Macintosh двоичный список свойств, создаваемый на основанном на PowerPC Macintosh.

Сериализация списка свойств APIs позволяет Вам сохранять графики объектов списка свойств как двоичные данные, а также списки свойств XML. Посмотрите Представления Списка свойств для относительных преимуществ и недостатков XML и двоичных списков свойств.

Сохранение и восстановление списка свойств в Objective C

NSPropertyListSerialization класс (доступный в OS X v10.2 и позже) обеспечивает методы для сохранения и восстановления списков свойств от двух главных поддерживаемых форматов, XML и двоичного файла. Для сохранения списка свойств в формате XML вызовите dataFromPropertyList:format:errorDescription: метод, указывая NSPropertyListXMLFormat_v1_0 как второй параметр; для сохранения в двоичном формате указать NSPropertyListBinaryFormat_v1_0 вместо этого.

Перечисление 5-1 сохраняет граф объектов объектов списка свойств как список свойств XML в комплекте приложений.

Перечисление 5-1  , Сохраняющее список свойств как список свойств XML (Objective C)

id plist;       // Assume this property list exists.
NSString *path = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"plist"];
NSData *xmlData;
NSString *error;
 
xmlData = [NSPropertyListSerialization dataFromPropertyList:plist
                                       format:NSPropertyListXMLFormat_v1_0
                                       errorDescription:&error];
if(xmlData) {
    NSLog(@"No error creating XML data.");
    [xmlData writeToFile:path atomically:YES];
}
else {
    NSLog(error);
    [error release];
}

Поскольку Вы не можете сохранить список свойств в старого стиля (OpenStep) формат, единственные параметры допустимого формата для этого метода NSPropertyListXMLFormat_v1_0 и NSPropertyListBinaryFormat_v1_0. NSData объект, возвращенный dataFromPropertyList:format:errorDescription: инкапсулирует XML или двоичных данных. Можно тогда вызвать writeToFile:atomically: или writeToURL:atomically: метод, чтобы хранить данные в файловой системе.

Для восстановления списка свойств от объекта данных путем десериализации его вызовите propertyListFromData:mutabilityOption:format:errorDescription: метод класса NSPropertyListSerialization класс, передающий в объекте данных. Перечисление 5-2 создает неизменный список свойств из файла в path:

Перечисление 5-2  , Восстанавливающее список свойств (Objective C)

NSString *path = [[NSBundle mainBundle] pathForResource:@"Data" ofType:@"plist"];
NSData *plistData = [NSData dataWithContentsOfFile:path];
NSString *error;
NSPropertyListFormat format;
id plist;
 
plist = [NSPropertyListSerialization propertyListFromData:plistData
                                mutabilityOption:NSPropertyListImmutable
                                format:&format
                                errorDescription:&error];
if(!plist){
    NSLog(error);
    [error release];
}

Опциональный параметр переменчивости метода десериализации управляет, создаются ли десериализованные объекты списка свойств как непостоянные или неизменные. Можно указать, что все объекты являются неизменными, что только контейнерные объекты являются непостоянными, или что все объекты являются непостоянными. Если у Вас нет определенной причины видоизменить наборы и другие объекты в десериализованном списке свойств, используйте неизменную опцию. Это быстрее и использует меньше памяти.

Последние два параметра propertyListFromData:mutabilityOption:format:errorDescription: ссылкой. По возврату из вызова параметр формата содержит постоянное указание дискового формата списка свойств: NSPropertyListXMLFormat_v1_0, NSPropertyListBinaryFormat_v1_0, или NSPropertyListOpenStepFormat. Можно передать в NULL если Вы не интересуетесь форматом.

Если возвращается вызов метода nil, заключительный параметр — строка описания ошибки — утверждает причину, за которой не следовала десериализация.

Сохранение и восстановление списка свойств в базовой основе

Property List Services Базовой Основы имеет функции сериализации, соответствующие методам класса NSPropertyListSerialization описанный в Сохранении и Восстановлении Списка свойств в Objective C. Для создания списка свойств XML из объекта списка свойств вызовите CFPropertyListCreateXMLData функция. Для восстановления объекта списка свойств от данных XML вызовите CFPropertyListCreateFromXMLData функция.

Перечисление 5-3 показывает Вам, как создать сложный список свойств, преобразовать его в XML, запишите его в диск, и затем воссоздайте исходную структуру данных с помощью сохраненного XML. Для получения дополнительной информации об использовании CFDictionary объекты видят, что Наборы Программируют Темы для Базовой Основы.

Перечисление 5-3  Сохраняющие и восстанавливающие данные списка свойств (Базовая Основа)

#include <CoreFoundation/CoreFoundation.h>
 
#define kNumKids 2
#define kNumBytesInPic 10
 
CFDictionaryRef CreateMyDictionary( void );
CFPropertyListRef CreateMyPropertyListFromFile( CFURLRef fileURL );
void WriteMyPropertyListToFile( CFPropertyListRef propertyList,
            CFURLRef fileURL );
 
int main () {
   CFPropertyListRef propertyList;
   CFURLRef fileURL;
 
   // Construct a complex dictionary object;
   propertyList = CreateMyDictionary();
 
   // Create a URL that specifies the file we will create to
   // hold the XML data.
   fileURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault,
               CFSTR("test.txt"),       // file path name
               kCFURLPOSIXPathStyle,    // interpret as POSIX path
               false );                 // is it a directory?
 
   // Write the property list to the file.
   WriteMyPropertyListToFile( propertyList, fileURL );
   CFRelease(propertyList);
 
   // Recreate the property list from the file.
   propertyList = CreateMyPropertyListFromFile( fileURL );
 
   // Release any objects to which we have references.
   CFRelease(propertyList);
   CFRelease(fileURL);
   return 0;
}
 
CFDictionaryRef CreateMyDictionary( void ) {
   CFMutableDictionaryRef dict;
   CFNumberRef            num;
   CFArrayRef             array;
   CFDataRef              data;
 
   int                    yearOfBirth;
   CFStringRef            kidsNames[kNumKids];
 
   // Fake data to stand in for a picture of John Doe.
   const unsigned char pic[kNumBytesInPic] = {0x3c, 0x42, 0x81,
            0xa5, 0x81, 0xa5, 0x99, 0x81, 0x42, 0x3c};
 
   // Define some data.
   kidsNames[0] = CFSTR("John");
   kidsNames[1] = CFSTR("Kyra");
 
   yearOfBirth = 1965;
 
   // Create a dictionary that will hold the data.
   dict = CFDictionaryCreateMutable( kCFAllocatorDefault,
            0,
            &kCFTypeDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks );
 
   // Put the various items into the dictionary.
   // Because the values are retained as they are placed into the
   //  dictionary, we can release any allocated objects here.
 
   CFDictionarySetValue( dict, CFSTR("Name"), CFSTR("John Doe") );
 
   CFDictionarySetValue( dict,
            CFSTR("City of Birth"),
            CFSTR("Springfield") );
 
   num = CFNumberCreate( kCFAllocatorDefault,
            kCFNumberIntType,
            &yearOfBirth );
   CFDictionarySetValue( dict, CFSTR("Year Of Birth"), num );
   CFRelease( num );
 
   array = CFArrayCreate( kCFAllocatorDefault,
               (const void **)kidsNames,
               kNumKids,
               &kCFTypeArrayCallBacks );
   CFDictionarySetValue( dict, CFSTR("Kids Names"), array );
   CFRelease( array );
 
   array = CFArrayCreate( kCFAllocatorDefault,
               NULL,
               0,
               &kCFTypeArrayCallBacks );
   CFDictionarySetValue( dict, CFSTR("Pets Names"), array );
   CFRelease( array );
 
   data = CFDataCreate( kCFAllocatorDefault, pic, kNumBytesInPic );
   CFDictionarySetValue( dict, CFSTR("Picture"), data );
   CFRelease( data );
 
   return dict;
}
 
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;
}

Для обсуждения опционального параметра переменчивости CFPropertyListCreateFromXMLData посмотрите обсуждение соответствующего параметра propertyListFromData:mutabilityOption:format:errorDescription: метод в Сохранении и Восстановлении Списка свойств в Objective C.

Перечисление 5-4 показывает как содержание xmlData, создаваемый в Перечислении 5-1, посмотрел бы, если распечатано на экран.

  Содержание XML-файла перечисления 5-4 создается примером программы

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
        "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Year Of Birth</key>
    <integer>1965</integer>
    <key>Pets Names</key>
    <array/>
    <key>Picture</key>
    <data>
        PEKBpYGlmYFCPA==
    </data>
    <key>City of Birth</key>
    <string>Springfield</string>
    <key>Name</key>
    <string>John Doe</string>
    <key>Kids Names</key>
    <array>
        <string>John</string>
        <string>Kyra</string>
    </array>
</dict>
</plist>
 

Используя службы списка свойств с какао

Какао использует Базовый список свойств Основы API, чтобы считать и записать списки свойств XML. В некоторых случаях можно хотеть получить доступ к API непосредственно в приложении Какао Objective C. Например, если Вы хотите сохранить экземпляр класса кроме NSArray или NSDictionary как корневой объект XML plist, в настоящее время самый простой способ сделать это через Property List Services. Этот процесс сделан простым, потому что объекты Какао могут быть брошены к и от соответствующих Базовых типов Основы. Это преобразование между Какао и Базовыми типами объектов Основы известно как бесплатное образование моста.

Для создания списка свойств XML из объекта списка свойств вызовите CFPropertyListCreateXMLData функция. Этот фрагмент кода сохраняет список свойств plist в файл в path:

NSString *path = [NSString stringWithFormat:@"%@/MyData.plist", NSTemporaryDirectory()];
id plist;       // Assume this is a valid property list.
NSData *xmlData;
 
xmlData = (NSData *)CFPropertyListCreateXMLData(kCFAllocatorDefault,
                                               (CFPropertyListRef)plist);
[xmlData writeToFile:path atomically:YES];
[xmlData release];

Для восстановления объекта списка свойств от данных XML вызовите CFPropertyListCreateFromXMLData функция. Этот фрагмент кода восстанавливает список свойств от XML plist файл в path с непостоянными контейнерами, но неизменными листами:

NSString *path = [NSString stringWithFormat:@"%@/MyData.plist", NSTemporaryDirectory()];
NSString *errorString;
NSData *xmlData;
id plist;
 
xmlData = [NSData dataWithContentsOfFile:path];
plist = (id)CFPropertyListCreateFromXMLData(kCFAllocatorDefault,
                 (CFDataRef)xmlData, kCFPropertyListMutableContainers,
                 (CFStringRef *)&errorString);