rplankenhorn
rplankenhorn

Reputation: 2084

iOS - PLIST - Access other plist values from within plist

I have a PLIST file in my app that contains various configuration data. Some of the data are URLs for accessing a server. This server hosts JSON files for several different versions of our code. What I want to be able to do is have a value in the PLIST file that has the version and then be able to reference it from other values. So the url value in the plist could be https://www.company.com/${VERSION}/jsonfile.svc (where ${VERSION} is a different key int he same plist file).

Upvotes: 2

Views: 443

Answers (2)

gberginc
gberginc

Reputation: 447

As bshirley mentioned there is nothing automatic but Objective-C can help you with that. Below is a simple implementation of a NSDictionary category called VariableExpansion that demonstrates how this could be implemented (note that this is not fully tested but serves primarily to demonstrate the way you could make this automatic. Also, expandedObjectForKey assumes you are dealing with NSStrings so you might need to tweak it a bit.

// In file NSDictionary+VariableExpansion.h
@interface NSDictionary (VariableExpansion)

- (NSString*)expandedObjectForKey:(id)aKey;

@end

// In file NSDictionary+VariableExpansion.m
#import "NSDictionary+VariableExpansion.h"

@implementation NSDictionary (VariableExpansion)

- (NSString*)expandedObjectForKey:(id)aKey
{
    NSString* value = [self objectForKey:aKey];

    NSError *error = NULL;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\$\\{([^\\{\\}]*)\\}"
                  options:NSRegularExpressionCaseInsensitive
                  error:&error];

    __block NSMutableString *mutableValue = [value mutableCopy];
    __block int offset = 0;

    [regex enumerateMatchesInString:value options:0
                  range:NSMakeRange(0, [value length]) usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop)
    {
    NSRange matchRange = [match range];
    matchRange.location += offset;

    NSString* varName = [regex replacementStringForResult:match
                           inString:mutableValue
                             offset:offset
                           template:@"$1"];

    NSString *varValue = [self objectForKey:varName];
    if (varValue)
    {
        [mutableValue replaceCharactersInRange:matchRange
                    withString:varValue];
        // update the offset based on the replacement
        offset += ([varValue length] - matchRange.length);
    }
    }];

    return mutableValue;
}

@end


// To test the code, first import this category:
#import "NSDictionary+VariableExpansion.h"

// Sample NSDictionary.
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
        @"http://${HOST}/${VERSION}/bla", @"URL",
        @"1.0", @"VERSION",
        @"example.com", @"HOST", nil];

// And the new method that expands any variables (if it finds them in the PLIST as well).
NSLog(@"%@", [dict expandedObjectForKey:@"URL"]);

The result of the last step is http://example.com/1.0/bla showing that you could use multiple variables in a single value. If a variable is not found it will not be touched in your original string.

Since you are using PLIST as your source, use dictionaryWithContentsOfFile as in

    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath];

Upvotes: 3

bshirley
bshirley

Reputation: 8357

have you tried anything? this is fairly straightforward, convert it as you are mentioning, the method of particular use: stringByReplacingOccurrencesOfString:.

Upvotes: 0

Related Questions