2015-04-20 1 views
0

Я уже рассматривал Parse Plist (NSString) into NSDictionary и считал, что это не дубликат, так как этот вопрос и его ответ не затрагивают мои проблемы.Как получить значения из многоуровневого .plist?


У меня есть .plist файла в файловой системе структурированной так:

Root > My App > Side Panel > Items > Price

Исходный код этого .plist файла выглядит следующим образом:

{ 
    "My App" = { 
     "Side Panel" = { 
      Items = { 
       Price = "#123ABC"; 
      }; 
     }; 
    }; 
} 

I знаете, как получить товар в Root вот так:

[[NSBundle mainBundle] pathForResource:@"filename" ofType:@"plist"]; 
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; 
NSString value = [dict objectForKey:@"key"]); 

Но что, если структура похожа на мою, с многоуровневыми словарями? Как получить значение Price?

Я хотел бы сделать это все в одном методе, в идеале, как это:

Вызов

NSString *hexString = [self getColorForKey:@"My App.Side Panel.Items.Price"]; 

Определение

- (NSString *) getColorForKey: (NSString *)key 
{ 
    NSArray *path = [key componentsSeparatedByString:@"."]; 
    NSDictionary *colors = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Colors" ofType:@"plist"]]; 
    NSString *color = @"#FFFFFF"; // white is our backup 

    // What do I put here to get the color? 

    return color; 
} 
+0

возможно дубликат [Анализировать Plist (NSString) в NSDictionary] (http://stackoverflow.com/questions/1072308/parse-plist-nsstring-into-nsdictionary) –

+0

@LouisTur Что касается тот, который разобранного из строка в памяти, и я не вижу, как это или ее ответы применимы к моей проблеме. –

+0

@ LouisTur да, этот ответ мне совсем не помогает. Не могли бы вы рассказать о том, как вы думаете, что это связано? Возможно, лучше узнать о вашем мыслительном процессе. –

ответ

0

Вот решение, которое работает для меня:

+ (NSString*) getHexColorForKey:(NSString*)key 
{ 
    NSArray *path = [key componentsSeparatedByString:@"."]; 
    NSDictionary *colors = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Colors" ofType:@"plist"]]; 
    NSString *color = @"#FFFFFF"; 
    for (NSString *location in path) { 
     NSObject *subdict = colors[location]; 
     if ([subdict isKindOfClass:[NSString class]]) 
     { 
      color = (NSString*)subdict; 
      break; 
     } 
     else if ([subdict isKindOfClass:[NSDictionary class]]) 
     { 
      colors = (NSDictionary*)subdict; // if it's a dictinoary, our color may be inside it 
     } 
     else 
     { 
      [SilverLog level:SilverLogLevelError message:@"Unexpected type of dictinoary entry: %@", [subdict class]]; 
      return color; 
     } 
    } 
    return color; 
} 

, где key - это NSString, что соответствует /^[^.]+(\.[^.]+)*$/, что означает, что это мой адрес @"My App.Side Panel.Items.Price".

0

Да Я понимаю, что вы хотите выполнить; Спасибо за уточнение. Однако я добавлю, что ресурсы и советы, которые я написал, предоставляют необходимую информацию для решения вашей проблемы.

Это говорит следующее получает свой словарь:

NSURL *plistURL = [[NSBundle mainBundle] URLForResource:@"Info" withExtension:@"plist"]; 
NSData *plistData = [NSData dataWithContentsOfURL:plistURL]; 
NSDictionary *tieredPlistData = [NSPropertyListSerialization propertyListWithData:plistData 
                      options:kCFPropertyListImmutable 
                      format:NULL 
                      error:nil]; 

Тогда, если мы заинтересованы в информации, содержащейся в Items

NSDictionary *allItemsDictionary = tieredPlistData[@"My App"][@"Side Panel"][@"Items"]; 

Items Предполагая, что будет содержать ряд объектов, вы можете использовать

Или, если есть одно значение вам нужно, то просто ссылаться, что ключевые

NSString *colorForPriceText = allItemsDictionary[@"Price"]; 

Но несколько советов:

  • Это обычно считается лучшей идеей, чтобы сохранить часто используемые значения в коде вместо PLIST/файл, который загружается во время выполнения.
  • Тем не менее, вы не ставили бы ваш звонок для загрузки с NSBundle тем же методом, который вы использовали бы для запроса определенного значения. В вашем примере каждый раз, когда вам нужен цвет, вы снова получаете доступ к NSBundle и накапливаете ненужные выделения памяти. Один метод мог бы загрузить plist в iVar NSDictionary, а затем, что NSDictionary будет использоваться отдельно другим способом.
+0

Это работает, если есть два значения, называемые ценой? Скажем, «Моя панель приложений.Items.Price» и «My App.Printout.Items.Price»? –

+0

Ну, да и нет .. неважно, что они являются одним и тем же ключом, потому что путь к ним различен - один из них будет «plist [@« My App »] [@« Боковая панель »]. ..', а другой будет "plist [@" My App "] [@" Распечатка "] ...'. Но код в настоящее время не может попасть ко второму, потому что он жестко кодирует базовый путь как «allItemsDictionary = tieredPlistData [@« My App »] [@« Боковая панель »] [@« Элементы »]' –

+0

Я имею в виду ваше второе решение: 'NSString * colorForPriceText = allItemsDictionary [@" Цена "];' –