I cant read from my plist file

Discussion in 'iOS Programming' started by lxLionHartxl, Aug 24, 2011.

  1. lxLionHartxl macrumors newbie

    Joined:
    Jul 20, 2011
    #1
    Hi,

    I have a problem reading from my plist file. I have tried multiple methods and none are working. I am stuck on this for a long time. I have already seek countless helps and looked up for solutions. I don't know why is this taking too long for me to solve. So I need your help.

    Code:
    NSError *error;
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
        NSString *documentsDirectory = [paths objectAtIndex:0]; //2
        NSString *path = [documentsDirectory stringByAppendingPathComponent:@"EventAddress.plist"]; //3
        NSLog(@"%@", path);
        NSFileManager *fileManager = [NSFileManager defaultManager];
        
        if (![fileManager fileExistsAtPath: path]) //4
        {
            NSString *bundle = [[NSBundle mainBundle] pathForResource:@"EventAddress" ofType:@"plist"]; // 5
            
            [fileManager copyItemAtPath:bundle toPath: path error:&error]; //6
        }
        
        NSString *pathss = [[NSBundle mainBundle] bundlePath];
        NSLog(@"%@", pathss);
        NSArray* plist = [NSArray arrayWithContentsOfFile:path];
        NSLog(@"%@", plist);
    The last few lines are used because each time I want to assign the NSArray to the path location, I get 0x0 (nil). Below is the image of my plist.

    [​IMG]
     
  2. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #2
    1. You have 3 NSLog()'s in your code. Post their output, so we can see what you see when the code runs.

    2. Add an NSLog() before copyItemAtPath: that shows the actual path of the 'bundle' variable. Rerun the program and post the output.

    3. Add a check for the existence of a file at the path given by the 'bundle' variable. That is, confirm that the file you're trying to copy from exists. Post the output.

    4. You don't check the BOOL returned from copyItemAtPath:, so you have no way to tell whether it worked or it failed.


    The basic principle of all debugging is to confirm what you expect. If you don't confirm something, and blindly assume it works as expected, you can be wrong.

    If confirmation means checking the result after every step of a procedure, then that's what you have to do. You will find at a certain point that learning to use the debugger, and using it to step through procedures, is more useful than throwing in dozens of NSLog()'s.
     
  3. lxLionHartxl thread starter macrumors newbie

    Joined:
    Jul 20, 2011
    #3
    Code:
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"EventAddress.plist"]; //3
        NSLog(@"%@", path);
    /Users/melvinlai/Library/Application Support/iPhone Simulator/4.3.2/Applications/98E03140-5556-4EE9-B7E3-043247E96D10/Documents/EventAddress.plist

    Code:
    NSString *pathss = [[NSBundle mainBundle] bundlePath];
        NSLog(@"%@", pathss);
    /Users/melvinlai/Library/Application Support/iPhone Simulator/4.3.2/Applications/98E03140-5556-4EE9-B7E3-043247E96D10/EventsLocator.app

    Code:
    NSArray* plist = [NSArray arrayWithContentsOfFile:path];
        NSLog(@"%@", plist);
    2011-08-25 11:18:45.211 EventsLocator[7240:207] (null)
    This is the part I am most concern.

    Code:
    NSString *bundle = [[NSBundle mainBundle] pathForResource:@"EventAddress" ofType:@"plist"];
    Users/melvinlai/Library/Application Support/iPhone Simulator/4.3.2/Applications/98E03140-5556-4EE9-B7E3-043247E96D10/EventsLocator.app/EventAddress.plist

    By looking at the log files, cant I confirm that it exists?

    Since there is a ! in the if statement, that sentence is returning a FALSE. I made it TRUE to answer your 2nd request.
     
  4. chown33, Aug 24, 2011
    Last edited: Aug 24, 2011

    chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #4
    Not with your posted code. Your current code doesn't check whether the original file exists. It simply makes a path and then tries to copy from that path. If the bundle isn't building correctly, then what you expect (the file located at EventsLocator.app/EventAddress.plist) isn't really there.

    Confirming every step means exactly that: confirming every step, even the ones you firmly believe can't possibly be going wrong. Confirmation requires evidence. Without evidence, you haven't confirmed anything.

    You also haven't shown the code that tests the result returned from copyItemAtPath:. Describing the code is not the same as showing the code.

    Post your complete revised code, with the added NSLog()'s and any other changes. Also post a complete copy-and-paste of the NSLog() output, in a single post. We should be able to read the complete code, and the complete output, and the exact sequence should be clear. Posting only pieces makes it harder to understand what's happening overall.
     
  5. lxLionHartxl thread starter macrumors newbie

    Joined:
    Jul 20, 2011
    #5
    .

    Code:
    -(void)readFile{
        NSError *error;
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
        NSString *documentsDirectory = [paths objectAtIndex:0]; //2
        NSString *path = [documentsDirectory stringByAppendingPathComponent:@"EventAddress.plist"]; //3
        NSLog(@"%@", path);
        NSFileManager *fileManager = [NSFileManager defaultManager];
        
        if ([fileManager fileExistsAtPath: path]) //4
        {
            NSString *bundle = [[NSBundle mainBundle] pathForResource:@"EventAddress" ofType:@"plist"]; // 5
            NSLog(@"%@", bundle);
            [fileManager copyItemAtPath:bundle toPath: path error:&error]; //6
            NSLog(@"%@", fileManager);
        }
        
        NSString *pathss = [[NSBundle mainBundle] bundlePath];
        NSLog(@"%@", pathss);
        NSMutableArray *plist = [[[[NSDictionary dictionaryWithContentsOfFile:path] objectForKey:@"New Item"] mutableCopy] autorelease];
        NSLog(@"%@", plist);
    }
    NSLog below.

    011-08-25 13:22:41.345 EventsLocator[8389:207] /Users/melvinlai/Library/Application Support/iPhone Simulator/4.3.2/Applications/98E03140-5556-4EE9-B7E3-043247E96D10/Documents/EventAddress.plist

    2011-08-25 13:22:46.721 EventsLocator[8389:207] /Users/melvinlai/Library/Application Support/iPhone Simulator/4.3.2/Applications/98E03140-5556-4EE9-B7E3-043247E96D10/EventsLocator.app/EventAddress.plist

    2011-08-25 13:22:48.374 EventsLocator[8389:207] <NSFileManager: 0x5807dc0>

    2011-08-25 13:22:50.633 EventsLocator[8389:207] /Users/melvinlai/Library/Application Support/iPhone Simulator/4.3.2/Applications/98E03140-5556-4EE9-B7E3-043247E96D10/EventsLocator.app

    2011-08-25 13:22:52.535 EventsLocator[8389:207] (null)


    Is this alright?
     
  6. lxLionHartxl thread starter macrumors newbie

    Joined:
    Jul 20, 2011
    #6
    solution

    Hi,

    do reply about this still. But I managed to find a code that got it working for me already. The codes are below. Thanks chown33 for your effort :)

    Code:
    NSString *path = [[NSBundle mainBundle] pathForResource:@"EventAddress" ofType:@"plist"]; 
        NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
        
        
        NSArray* allmyKeys = [myDictionary  allValues];
        NSLog(@"%@", allmyKeys);
        NSLog(@"%@", [[allmyKeys objectAtIndex:0] objectAtIndex:0]);
    The last 2 NSLog is used to see if my plist does return an array of values and to find out the value of only 1 of them. And thanks a lot about the debugger, after looking at it for almost 3 days straight, I also realized my problem. The damn array isn't the normal one dimension, its TWO DIMENSION. Thats why I used objectAtIndex twice. :)
     
  7. chown33, Aug 25, 2011
    Last edited: Aug 25, 2011

    chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #7
    It's not what I suggested:
    You aren't doing either of those things.

    To do #3, you'd add code something like this (untested, typed in directly):
    Code:
    BOOL exists = [fileManager fileExistsAtPath: bundle];
    NSLog(@"bundle exists: %d", (int)exists );
    
    This should go before the copyItemAtPath:bundle.

    To do #4, you'd add code something like this (also untested):
    Code:
    BOOL copied = [fileManager copyItemAtPath:bundle toPath: path error:&error]; //6
    NSLog(@"copied: %d", (int) copied );
    if ( ! copied )
    {  ... do something to handle the error ... }
    
    If the output confirms that the file exists, and is correctly copied, then you have evidence it was actually copied. If the output shows otherwise, then you have evidence it wasn't.

    The NSLog of fileManager is misplaced, if you expect it to be confirmation of a non-nil NSFileManager. It should be placed before the first use of fileManager. Then you can say it confirms the object's existence before it's used. Where it's placed now, it's too late to confirm anything.

    Confirmation is a step-by-step trail of evidence. It should show that what you expect to happen is actually happening. Every piece of evidence should answer a logically relevant question: What is this value at this point? Did something just complete successfully or not?


    As it turns out, the problem wasn't in the file-copying, or even the loading of the file. The problem was in not using the resulting plist object correctly.

    You should be able to design and write code that confirms the contents of a plist object. Knowing how to confirm things means you have to understand what things really are. If you don't really understand what things are, then you won't know what to confirm. The process of thinking about how to confirm something can lead you to a better understanding of what it is, or it can even correct a misunderstanding.


    Code:
    NSString *path = [[NSBundle mainBundle] pathForResource:@"EventAddress" ofType:@"plist"]; 
        NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
    
    If that code works, then it suggests your plist file isn't what you originally posted. Your original post shows an Array containing two Strings.

    If you only showed part of your plist, then the lesson is to use the entire plist, not just one part, and to post complete data, not just one part.

    If you changed what's in your plist, then the lesson is to show what you changed.

    There could be other reasons why that code works. It's impossible to say without seeing the complete plist data.

    Code:
        NSArray* allmyKeys = [myDictionary  allValues];
    
    The name of the variable allmyKeys is misleading. It actually holds all the values from the dictionary, not all the keys.

    You should also read the reference doc on allValues, where it says "The order of the values in the array isn’t defined." This means you can't rely on a particular value being at index 0 in the returned NSArray. Which means that your code relying on things being at index 0 could fail unexpectedly.
     
  8. lxLionHartxl thread starter macrumors newbie

    Joined:
    Jul 20, 2011
    #8
    Wow, this is s a lengthy message. Sorry, I don't work over the weekends. So I did not see this post until today. Thanks for the info, unfortunately, I have to agree with you. I totally do not understand the plist thing. Will read your steps and try again hopefully I would understand the plist better. And you are right, its the allValues that made it work :)

    And it may not be today or tomorrow, if I have anymore questions regarding the plist. Do I start a new topic or continue from here?
     

Share This Page