Plist Array в NSDictionary
У меня есть plist:
<plist version="1.0">
<array>
<dict>
<key>name</key>
<string>Alabama</string>
<key>abreviation</key>
<string>AL</string>
<key>date</key>
<string>1819</string>
<key>population</key>
<string>4,627,851</string>
<key>capital</key>
<string>Montgomery</string>
<key>largestCity</key>
<string>Birmingham</string>
</dict>
<dict>
<key>name</key>
<string>Alaska</string>
<key>abreviation</key>
<string>AK</string>
<key>date</key>
<string>1959</string>
<key>population</key>
<string>683,478</string>
<key>capital</key>
<string>Juneau</string>
<key>largestCity</key>
<string>Anchorage</string>
</dict>
...
</array>
</plist>
Я пытаюсь загрузить его в NSDictionary следующим образом:
NSString *path = [[NSBundle mainBundle] pathForResource:@"stateInfo" ofType:@"plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:path]) {
NSLog(@"The file exists");
} else {
NSLog(@"The file does not exist");
}
NSMutableDictionary *myDic = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
//NSDictionary *myDic = [NSDictionary dictionaryWithContentsOfFile:path];
NSLog(@"The count: %i", [myDic count]);
NSArray *thisArray = [[NSArray alloc] initWithContentsOfFile:path];
NSLog(@"The array count: %i", [thisArray count]);
Я всегда получаю массив, равный 50, но значение словаря 0. Поэтому я попытался перебрать массив и добавить его в словарь:
NSDictionary *eachState;
for (eachState in thisArray) {
State *thisState = [[State alloc] initWithDictionary:eachState];
[myDic setObject:thisState forKey:thisState.name];
}
Но цикл генерирует исключение:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '*** -[NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
Состояние - это класс со свойствами, соответствующими моему plist. Что я делаю не так? Я вижу здесь всевозможные связанные вопросы, но я не могу это понять.
Ответы
Ответ 1
Две проблемы:
- Загрузка plist в NSDictionary:
Это простая проблема, которая, кажется, вы уже поняли. Глобальный объект в вашем plist - это массив, а не dict, поэтому, когда вы загружаете его в словарь, он не знает, что делать (несовместимые типы), поэтому вы получаете пустой словарь.
- Цитирование через ряд словарей:
Из Исключения, которое вы получаете, вы вызываете "setObject: forKey:" в словаре, который инициализируется как NSDictionary, а не NSMutableDictionary. Указатель набирается как NSMutableDictionary, но не фактический объект памяти. Вам нужно изменить свою линию.
NSMutableDictionary *myDic = [[NSDictionary alloc] initWithContentsOfFile:path];
к
NSMutableDictionary *myDic = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
и фактически, поскольку загрузка словаря из файла дает вам пустой словарь, вы тратите впустую циклы, пытаясь загрузить его из файла, и должны просто создать новый:
NSMutableDictionary *myDic = [[NSMutableDictionary alloc] init];
Ответ 2
Более гибкий способ загрузки plists в память, который также позволяет создавать изменяемые plists:
NSData* data = [NSData dataWithContentsOfFile:path];
NSMutableArray* plist = [NSPropertyListSerialization propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:NSPropertyListXMLFormat_v1_0
errorDescription:NULL];
Таким образом, ваш код может быть реализован как:
NSString *path = [[NSBundle mainBundle] pathForResource:@"stateInfo" ofType:@"plist"];
NSData* data = [NSData dataWithContentsOfFile:path];
NSMutableArray* array = [NSPropertyListSerialization propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:NSPropertyListXMLFormat_v1_0
errorDescription:NULL];
if (array) {
NSMutableDictionary* myDict = [NSMutableDictionary dictionaryWithCapacity:[array count]];
for (NSDictionary* dict in array) {
State* state = [[State alloc] initWithDictionary:dict];
[myDict setObject:state forKey:state.name;
[state release];
}
NSLog(@"The count: %i", [myDic count]);
} else {
NSLog(@"Plist does not exist");
}