Reading plist file
Asked Answered
H

2

10

I created plist with big base of different animals in it (keys) and added this plist in my project. Type of every animal is NSDictionary. In every dictionary there are 5 more keys - characteristics of these animals (). I would like to go through every animal and if I match a certain characteristics of this animal, I put this animal in another array.

So, I tried to make a code:

NSArray *newArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"animals" ofType:@"plist"]];    

for (int i = 0;[newArray objectAtIndex:i];i++)    
{      
      if ([[newArray objectAtIndex:i]objectForKey:@"minAge"] == [NSNumber numberWithInt:3]) 
      {            
              [array addObject:[[newArray objectAtIndex:i]objectForKey:@"name"]];                  
      }
}

So objectAtIndex:i is an animal and minAge is one of it's characteristics. But my code does not work. I do it for the first time, so what I have done wrong ? Thanks!

UPDATE: Thank you, your plist works normally ! But I still cant understand why doesn't work mine plist: My plist was looking like this

Anyway, thank you so much ! I didn't eat and sleep while I was solving this problem :) You helped me a lot !

Hyperbolize answered 6/1, 2012 at 13:10 Comment(0)
W
26

NSArray The Return value will be nil if the file can’t be opened or if the contents of the file can’t be parsed into an array.

I suspect the issue is you need to put the contents in a NSDictionary rather than a NSArray

 NSDictionary *theDict = [NSDictionary dictionaryWithContentsOfFile:plistFile];

Edit.Further to my answer

NSMutableArray *mutableArray =[[NSMutableArray alloc] initWithObjects:nil];
NSDictionary *mainDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"animals" ofType:@"plist"]];

   //--get parent dictionary/Array named animals which holds the animals dictionary items
    NSDictionary *parentDictionary = [mainDictionary objectForKey:@"animals"];


    //---enumerate through the dictionary objects inside the parentDictionary
    NSEnumerator *enumerator = [parentDictionary objectEnumerator];
    id value;

    while ((value = [enumerator nextObject])) {
        if ([[value valueForKey:@"minAge"] isEqualToNumber:[NSNumber numberWithInt:3]]) 
        {            

            [mutableArray addObject:[value valueForKey:@"name"]];                  
        }


    }

If the animal dictionaries are not inside of a parent dictionary or Array, use something like this

NSMutableArray *mutableArray =[[NSMutableArray alloc] initWithObjects:nil];

    NSDictionary *mainDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"animals" ofType:@"plist"]];




    //---enumerate through the dictionary objects 
    NSEnumerator *enumerator = [mainDictionary objectEnumerator];
    id value;

    while ((value = [enumerator nextObject])) {
        if ([[value valueForKey:@"minAge"] isEqualToNumber:[NSNumber numberWithInt:3]]) 
        {            

            [mutableArray addObject:[value valueForKey:@"name"]];                  
        }


    }

Edit. 1.

Try it with this plist. Make sure you use a plain text editor to paste it into and save as a plist file

Edit.2 . I have now updated my plist to match yours. Although the other one worked. I felt it would make more sense that we are using the same.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Whale</key>
    <dict>
        <key>name</key>
        <string>Whale</string>
        <key>isMale</key>
        <true/>
        <key>color</key>
        <string>blue</string>
        <key>maxAge</key>
        <integer>8</integer>
        <key>minAge</key>
        <integer>3</integer>
    </dict>
    <key>Dolphin</key>
    <dict>
        <key>maxAge</key>
        <integer>20</integer>
        <key>name</key>
        <string>Dolphin</string>
        <key>isMale</key>
        <false/>
        <key>color</key>
        <string>blue</string>
        <key>minAge</key>
        <integer>15</integer>
    </dict>
</dict>
</plist>

Also, here is another example showing how to compare the boolean and number together

NSMutableArray *theAnimalMatched =[[NSMutableArray alloc] initWithObjects:nil];


    NSDictionary *mainDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"data1" ofType:@"plist"]];



    //---enumerate through the dictionary objects inside the rootDictionary
    NSEnumerator *enumerator = [mainDictionary objectEnumerator];
    id returnValue;

 while ((returnValue = [enumerator nextObject])) {

         if ( [[returnValue valueForKey:@"isMale" ] boolValue] && [[returnValue valueForKey:@"minAge"] isEqualToNumber:[NSNumber numberWithInt:3]] && [[returnValue valueForKey:@"color"] isEqualToString:@"blue"]  )  
         {  

        [theAnimalMatched addObject:[returnValue valueForKey:@"name"]];                  
    }


}
Worldwide answered 6/1, 2012 at 13:10 Comment(11)
Thank you markhunte! Yes, array returns nil in the console. I tried your code but it also doesnt work. Maybe I have problems with my plist file ?Hyperbolize
I just put a example plist in my answer. Try it with that.Worldwide
Wow, it works perfectly ! Thank you so much ! Please, check my main message :)Hyperbolize
Just to clarify my last comment. Did you run your plist, through the code for no parent dictionary/arrayWorldwide
I tried both codes and, of course, with no parent dictionary code my app just crashes.Hyperbolize
What is the crash error??. Also can you send me the plist file. Here is a temporary email address: [email protected]Worldwide
Sure, here is the error message: [_NSArrayI isEqualToNumber:]: unrecognized selector sent to instance 0x6a41d20 2012-01-07 20:23:36.724 GiftBoxOne[16269:f803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_NSArrayI isEqualToNumber:]: unrecognized selector sent to instance 0x6a41d20' Actually, I have the same plist in the picture above.Hyperbolize
The problem there is you are trying to compare an object that is not a number. Meaning for example a string value is not a number. You cannot use isEqualToNumber: to compare objects that are not NSNumbers. I suspect you are using the same example code that @Aadhira suggested, for all your comparisons. You should use the correct ones for strings, booleansWorldwide
I have update my answer again.So you can see how to do the boolean and matched my plist with yoursWorldwide
Thats right, thanks! Your code runs perfectly so now I can combine my plist to it. Btw, do you know how to compare NSNumber with integer? Or should I convert NSNumber to integer and then compare them with >= or <= operators ?Hyperbolize
Oh, got it. age >= [[returnValue valueForKey:@"minAge"] intValue] && age <= [[returnValue valueForKey:@"maxAge"] intValue])Hyperbolize
B
0

Instead of the following line

 if ([[newArray objectAtIndex:i]objectForKey:@"minAge"] == [NSNumber numberWithInt:3]) 

try the following

 if ( [[[newArray objectAtIndex:i]objectForKey:@"minAge"] isEqualToNumber:[NSNumber numberWithInt:3]]) 
Bicipital answered 6/1, 2012 at 13:54 Comment(1)
Yees, thanks! I already fixed it. But unfortunally, it does not work. I think my problem caused by something else.Hyperbolize

© 2022 - 2024 — McMap. All rights reserved.