plist XML-строка в NSMutableDictionary

Я храню некоторые словари в файлах plist (iOS), которые впоследствии шифруются. После прочтения содержимого файла и его расшифровки я возвращаю xml-содержимое файла в виде строки:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>password</key>
    <string>apassword</string>
    <key>username</key>
    <string>ausername</string>
</dict>
</plist>

Мне известны методы dictionaryWithContentsOfFile:(NSString *) и dictionaryWithContentsOfFile:(NSURL *) для создания словаря на основе данных этого типа, но я удивлен, что таких dictionaryWithXML:(NSString *)

За исключением записи этих данных в файл, а затем их чтения, чего я пытался избежать, поскольку это просто чрезмерно, есть ли какие-то очевидные обходные пути, которые мне не хватает?


person amcc    schedule 22.02.2013    source источник
comment
возможный дубликат Разобрать Plist (NSString) в NSDictionary   -  person ismail    schedule 28.02.2013


Ответы (2)


У NSPropertyListSerialization есть удобный метод, который сделает это за вас, читая из NSData экземпляра:

NSString *source = ... // The XML string

NSData* plistData = [source dataUsingEncoding:NSUTF8StringEncoding];

NSError *error;

NSMutableDictionary* plist = [NSPropertyListSerialization propertyListWithData:plistData
                                                                       options: NSPropertyListImmutable
                                                                        format:NULL
                                                                         error:&error];

Как указал @Adam в комментариях, словарь, возвращаемый этим методом, всегда изменяемый. Параметр options служит для определения, являются ли контейнеры (массивы, словари), содержащиеся в списке, также изменяемыми или (по умолчанию) неизменяемыми.

Если вы хотите, чтобы контейнеры в списке свойств также были изменяемыми, вы можете использовать NSPropertyListMutableContainers - или NSPropertyListMutableContainersAndLeaves, если вам нужно, чтобы даже листья были изменяемыми.

person Monolo    schedule 22.02.2013
comment
Метод propertyListWithData:options:format:error: всегда возвращает экземпляр NSMutableDictionary. Параметр options влияет на его содержимое. - person Adam; 22.02.2013
comment
@Adam Я только что протестировал это с NSPropertyListImmutable и получил __NSCFDictionary, который, я считаю, неизменен, так что, может быть, мы не говорим об одном и том же? - person Monolo; 22.02.2013
comment
@Monolo __NSCFDictionary - это частный класс кластера классов. NSMutableDictionary может быть экземпляром __NSCFDictionary или __NSDictionaryM или любого другого класса, который Apple решит использовать под капотом. AFAIK, __NSCFDictionary может быть изменяемым или неизменным. Чтобы проверить изменчивость, я бы сделал следующее: [dict isKindOfClass:[NSMutableDictionary class]]. - person Adam; 22.02.2013

Как сказал @Monolo в своем ответе, NSPropertyListSerialization - это путь. Однако вы можете получить NSMutableDictionary, не копируя данные в новый экземпляр. Вот код:

NSString *str = @"<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd\"><plist version=\"1.0\"><dict><key>password</key><string>apassword</string><key>username</key><string>ausername</string></dict></plist>";
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
NSPropertyListFormat format;
NSMutableDictionary *dict = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:&format error:&err];
if (err) {
    NSLog(@"err: %@", err);
}
NSLog(@"original dictionary: %@", dict);
[dict setValue:@"newPass" forKey:@"password"];
NSLog(@"modified dictionary: %@", dict);
person Adam    schedule 22.02.2013