Search code examples
iosdictionarytreeplist

How do I get values from a tiered .plist?


I've already looked at Parse Plist (NSString) into NSDictionary and deemed it to be not a duplicate, as that question and its answer do not address my concerns.


I have a .plist file in the file system structured like this:

Root > My App > Side Panel > Items > Price

The source code of this .plist file looks like this:

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

I know how to get an item in the Root like this:

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

But what if the structure is like mine, with tiered dictionaries? How do I get the value of Price?

I would like to do this all in one method, ideally like this:

Calling

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

Definition

- (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;
}

Solution

  • Here's the solution that worked for me:

    + (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;
    }
    

    where key is an NSString that matches /^[^.]+(\.[^.]+)*$/, meaning it looks like my targeted @"My App.Side Panel.Items.Price".