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");
}