【问题标题】:How do I get values from a tiered .plist?如何从分层 .plist 中获取值?
【发布时间】:2015-06-27 12:02:49
【问题描述】:

我已经查看了 Parse Plist (NSString) into NSDictionary 并认为它不是重复的,因为该问题及其答案并未解决我的担忧。


我在文件系统中有一个.plist 文件,其结构如下:

这个.plist文件的源代码如下:

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

我知道如何像这样在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;
}

【问题讨论】:

  • @LouisTur 它处理的是从内存中的字符串解析出来的,我看不出它或其答案如何适用于我的问题。
  • @LouisTur 是的,这个答案对我一点帮助都没有。你能详细说明你认为它是如何相关的吗?也许更多地了解你的思维过程会有所帮助。
  • 您是在问如何到达NSDictionary 中的子节点吗?它在概念上与获取根节点NSString *price = dict[@"Root"][@"MyApp"][@"Side Panel"][@"Items"][@"Price"] 相同。使用 KVO 也是一种可能。遍历字典是一个基本概念,无论您的数据源如何,我都会在发布之前快速搜索该主题。但这可能会有所帮助:appventure.me/2011/12/07/…
  • @LouisTur 我添加了一个示例案例,说明我想如何做到这一点。这是否有助于您理解我的问题?

标签: ios dictionary tree plist


【解决方案1】:

这是对我有用的解决方案:

+ (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"

【讨论】:

    【解决方案2】:

    是的,我了解您要完成的工作;谢谢你的澄清。但是,我要补充一点,我所写的资源和建议确实提供了解决您的问题的必要信息。

    也就是说,以下内容会获取您的字典:

    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 将包含许多对象,您可以使用

    NSArray *keys = [allItems allKeys];
    for(NSString *key in keys){
        NSString *colorValue = allItemsDictionary[key];
        // do something with said color value and key
    }
    

    或者,如果您需要一个值,则只需引用该键

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

    但有一些提示:

    • 通常认为将经常访问的值保存在代码中而不是在运行时加载的 plist/文件中是一个更好的主意。
    • 也就是说,您不会以与查询特定值相同的方法调用从NSBundle 加载。在您的示例中,每次需要颜色时,您最终都会重新访问 NSBundle 并堆积不需要的内存分配。一种方法是将 plist 加载到 iVar NSDictionary 中,然后 NSDictionary 将由另一种方法单独使用。

    【讨论】:

    • 如果有两个称为价格的值,这是否有效?比如My App.Side Panel.Items.PriceMy App.Printout.Items.Price?
    • 嗯,是的,也不是......它们是同一个键并不重要,因为到达它们的路径不同——一个是plist[@"My App"][@"Side Panel"]...,另一个是@987654334 @。但是代码目前无法到达第二个,因为它将基本路径硬编码为allItemsDictionary = tieredPlistData[@"My App"][@"Side Panel"][@"Items"]
    • 我的意思是你的第二个解决方案:NSString *colorForPriceText = allItemsDictionary[@"Price"];
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-27
    • 1970-01-01
    • 1970-01-01
    • 2011-03-07
    • 1970-01-01
    • 1970-01-01
    • 2015-08-18
    相关资源
    最近更新 更多