xonegirlz
xonegirlz

Reputation: 8967

reading a NSDictionary from plist issue with BOOL value

So I have the following method:

- (void)readPlist
{

    NSString *path = [[NSBundle mainBundle] pathForResource:@"States" ofType:@"plist"];    
    self.data = [[NSMutableDictionary alloc] initWithContentsOfFile:path];

    BOOL value = (BOOL)[self.data valueForKey:@"Arizona"];
    NSLog(@"VALUE IS %d", value);

}

It reads the plist fine, it can detect that it has 7 keys, however when I try to print the value out it gives me 32 if it's a no and 24 if it's a yes. What am I doing wrong?

Upvotes: 9

Views: 6787

Answers (3)

Max MacLeod
Max MacLeod

Reputation: 26652

Thought I would chip in on this. First thing is, how to property define a BOOL value in your plist?

Apple's DTD for plist gives a decent clue:

<!ENTITY % plistObject "(array | data | date | dict | real | integer | string | true | false )" >

and later:

<!-- Numerical primitives -->
<!ELEMENT true EMPTY>  <!-- Boolean constant true -->
<!ELEMENT false EMPTY> <!-- Boolean constant false -->

All great, but how does that look in the plist?

Well, for a true value, it would be:

    <dict>
        <key>employeeId</key>
        <integer>1</integer>
        <key>name</key>
        <string>Joe Smith</string>
        <key>worksRemotely</key>
        <true/>
    </dict>

and of course for false:

    <dict>
        <key>employeeId</key>
        <integer>1</integer>
        <key>name</key>
        <string>Joe Smith</string>
        <key>worksRemotely</key>
        <false/>
    </dict>

To create an object from the plist, as a keen user of Objectify, I take inspiration from their factory classes. My Employee class would have these methods:

+ (Employee *)instanceFromDictionary:(NSDictionary *)aDictionary {

    Employee *instance = [[Employee alloc] init];

    [instance setAttributesFromDictionary:aDictionary];
    return instance;
}

that in turn calls:

- (void)setAttributesFromDictionary:(NSDictionary *)aDictionary {

    if (![aDictionary isKindOfClass:[NSDictionary class]]) {
        return;
    }

    [self setValuesForKeysWithDictionary:aDictionary];

}

setValuesForKeysWithDictionary:aDictionary is a member of the NSKeyValueCoding Protocol. That's available with every NSObject which means as as a subclass of NSObject, our Employee class gets that for free.

As long as my Employee class' properties match with the key values specified in the plist, namely employeeId, name, and worksRemotely, then I won't need to do anything else. That method will translate the worksRemotely boolean specified in the plist to the correct value in my class instance:

@property (assign, nonatomic, getter = isWorkingRemotely) BOOL worksRemotely;

All that's left is to iterate through the plist contents, creating the instances of my desired class, bool included:

NSString *plistPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"employees" ofType:@"plist"];
NSArray *employeeDictionaries = [NSArray arrayWithContentsOfFile:plistPath];
for (NSDictionary *employeeDict in employeeDictionaries) {
     Employee *employee = [Employee instanceFromDictionary:employeeDict];
     [employees addObject:employee];
}

No doubt I've gone a bit over the top in answering the specific question. However hopefully this can be of use to someone else who stumbled across this question whilst trying to do what I was trying, i.e. create a class with a boolean value in a plist.

Upvotes: 0

Colin
Colin

Reputation: 3752

valueForKey returns an id. Do this:

NSNumber * n = [self.data valueForKey:@"Arizona"];
BOOL value = [n boolValue];

Upvotes: 24

Zigglzworth
Zigglzworth

Reputation: 6813

- (void)readPlist
{

NSString *path = [[NSBundle mainBundle] pathForResource:@"States" ofType:@"plist"];    
self.data = [[NSMutableDictionary alloc] initWithContentsOfFile:path];

BOOL value = [[self.data valueForKey:@"Arizona"] intValue];
NSLog(@"VALUE IS %i", value);

}

Upvotes: 1

Related Questions