views:

101

answers:

3

I have a pList file:

Root - Dictionary
  categories - Array
     item 0 - Dictionary
     item 1 - Dict
     item 2 - Dict

I load the file like so:

-(void) loadCategories
{
    // Loads the categories from the SymbolList.plist file
    NSString *file = [[NSBundle mainBundle] pathForResource:@"SymbolList" ofType:@"plist"];
    NSMutableDictionary *plistSymbolList = [[NSMutableDictionary alloc] initWithContentsOfFile:file];

    categoriesList = [plistSymbolList objectForKey:@"categories"];
    NSLog(@"count is: %d", [categoriesList count]); 

    // Here I am just testing if this method will work
    for(int i = 0; i < [categoriesList count]; i++)
    {
        NSDictionary *dict = [categoriesList objectAtIndex:i];
        NSLog(@"dict count: %d", [dict count]);
    }

    // ideally this is what I'd like to do but doesn't work on device
    for (NSDictionary *dictionary in categoriesList)
    {
        if (dictionary == nil)
            NSLog(@"It's nil.");

        NSLog(@"count: %d", [dictionary count]);

        // get and display the category information
        NSString *catName = [dictionary objectForKey:@"Category Name"];
        NSLog(@"catName is: %@", catName);
        NSString *catImage = [dictionary objectForKey:@"Category Image"]; 
        NSLog(@"catImage is: %@", catImage);

        NSString *fullFile = [NSString stringWithFormat:@"%@.png", catImage];
        NSLog(@"Full file name is: %@", fullFile);

        SymbolButton *categoryButton = [[SymbolButton alloc] initWithName:catName andSymbol:catImage];
        [categoryButton addTarget:self action:@selector(categoryButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
        [categoryButtonList addObject:categoryButton];
        NSLog(@"Added Button to list");
    }

    [self updateCategories];    

Just to recap I am: 1) loading the file to get my root 2) getting my list of categories 3) looping through each one and getting some value with either objectAtIndex OR objectForKey

ALL of this code works GREAT on the emulator and runs perfectly with no crashes. This function DIES as soon as I run it on the device:

TestApp[4734:207] count is: 3
TestApp[4734:207] *** -[NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x122d10
TestApp[4734:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x122d10'

From the error message it's saying there is an issue with my instances. But why would this work on the sim and not the device? Everything is updated to the latest SDK and OS version (non-beta) etc.

If I comment out the first for loop I get:

TestApp[4760:207] count is: 3
TestApp[4760:207] *** -[NSCFString count]: unrecognized selector sent to instance 0x120470
TestApp[4760:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFString count]: unrecognized selector sent to instance 0x120470'

Thanks for any and all help. This one is killing me :)

A: 

Three things: First I think you should be using valueForkey: not objectForKey: I'm presuming youve got String in your dictionary. Something like this:

NSString *catName = [dict valueForKey:@"Category Name"];

Second: why not move everything from NSString *catName = [dictionary objectForKey:@"Category Name"]; into the first for loop and do NSString *catName = [dict objectForKey:@"Category Name"]; instead? Should do the same job So you would have something like this:

for(int i = 0; i < [categoriesList count]; i++)
{
NSDictionary *dict = [categoriesList objectAtIndex:i];
NSLog(@"dict count: %d", [dict count]);
NSString *catName = [dict objectForKey:@"Category Name"];
NSLog(@"catName is: %@", catName);
NSString *catImage = [dict objectForKey:@"Category Image"];

}

Third: I dont think [dictionary count] will work, try taking that out.

Hope this helps

octermircty
Thanks for your help! I tried your suggestions. I am using a string for the value so switched it to valueForKey but saw no change. I also tried removing the [dictionary count]. Still no change. All this DOES work fine on the emulator but NOT on the device. Seems very strange. Any other ideas?
David Nelson
Also, why would this not work: NSDictionary *dictionary = (NSDictionary *)[categoriesList objectAtIndex:0];As this should return the first NSDictionary in categoriesList. Remember I know there are 3 objects in my list because I'm reporting the count of the list before I try and assign this.
David Nelson
A: 

You may be reading a different version of the plist file on the simulator than the one that's currently on the phone. The problem in the first loop is that apparently the categoriesList stored in the plist on the simulator is an array, whereas the one on the phone is a dictionary.

If you look carefully at the log message:

-[NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x120470

you'll see that it's telling you exactly what the problem is: you're sending an -objectAtIndex: message to an instance of NSDictionary (NSCFDictionary is a private subclass of NSDictionary).

Your code should be compiling with a warning on that line. A bit of advice: don't ignore warnings in Objective-C! They usually indicate serious problems, many of which may be runtime fatal.

The problem in the second loop is similar, and again, the log message is telling you everything you need to know: you're sending a -count message to an instance of NSString, which your code is apparently expecting to be an NSDictionary.

jlehr
Thanks for the advice. My code actually does not compile with any warnings or issues. Warnings are the same as errors to me and I never let them slide. The file on the device is the same file as on the emulator. I was worried about this and checked several times. The -count should be called on the Dictionary or List depending on where in the code you are referencing. The issue seems to be the devices dealing with a NSDict with a NSArray with multiple NSDicts under that. Seems strange.
David Nelson
Sorry, made a bad guess about the `categoriesList` ivar in the absence of a declaration. In any case, the problem results from a mismatch between the actual structure of the plist and what the code was expecting.
jlehr
A: 

Turns out that the issue is with a plist file having multiple types nested.

I had a plist file that was:

NSDictionary
 - NSArray
   - Item 0
     - Name - String
     - Category - String
     - Image - String
   - Item 1
     - Name - String
     - Category - String
     - Image - String
   - Item 2
     - Name - String
     - Category - String
     - Image - String

The emulator handled this fine loading as I mentioned above. However, the device simply would not read the members correctly.

I switched my plist file to be:

  NSArray
   - Item 0
     - Name - String
     - Category - String
     - Image - String
   - Item 1
     - Name - String
     - Category - String
     - Image - String
   - Item 2
     - Name - String
     - Category - String
     - Image - String

The root is an Array and it continues as normal from this point forward.

I thought maybe I was reading in an object when it should have been a value but this was not the case. However, the debug info points to this. This still seems strange, but it now works perfectly in both emulator and on the device.

I hope this helps anyone with this same issue.

David Nelson