NSMutableDictionary writeToFile:

Discussion in 'Mac Programming' started by larswik, Jul 17, 2011.

  1. larswik macrumors 68000

    Joined:
    Sep 8, 2006
    #1
    I must be over looking something simple here Rob helped me earlier on this same project. My Dictionary is called 'skills' and I am just trying now to write the Dictionary to the Hard Drive using this code
    Code:
       [skills writeToFile:@"/Users/test.plist" atomically:YES];
    When I look in the users folder there is no test.plist file? I read the documentation and searched on line and followed the examples. WriteToFile is a method of NSMutableDictionary.

    I am just storing information in the dictionary from 2 NSTextFields as the Object and Key With this code
    Code:
    [skills setObject:[skillBonusPrefField stringValue] forKey:[skillNamePref stringValue]]; 
    There must be a simple answers why I can't see the file, I hope
     
  2. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #2
    You'll find this call is failing and returning NO because users can't write to the /Users directory. Try writing into your subdirectory under /Users. For example, @"/Users/Lars/test.plist".
     
  3. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #3
    Yep, that was it. Thanks Jim. What if I give a version to a friend to try out? It will be looking for my name 'Lars'. Is there a common folder that I can put it in. I am guessing there is a way to bypass the username to add it to the Documents folder.

    This will keel me moving forward for now.

    Thanks again.
     
  4. blueillusion macrumors member

    Joined:
    Aug 18, 2008
  5. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #5
    The are few techniques you can use.

    The easiest is to use NSString's stringByExpandingTildeInPath which will expand ~ into the full path to the user's home directory.
    Code:
    NSString* fullPath = [@"~/test.plist" stringByExpandingTildeInPath];
    [skills writeToFile:fullPath atomically:YES];
    There are other techniques for find specific directories, such as the user's documents directory. See Creating Paths and Locating Directories.
     
  6. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #6
    Cool, I will read up on the stringByExpandingTildeInPath in the morning and add it in. I got a lot done today.

    Thanks for the help!
     
  7. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #7
    Thanks for the tip regarding the 'stringByExpandingTildeInPath'. It worked and I added the word Documents to the list so it writes it in the Documents folder. I am getting an error when I try to write to that file later in the program when I try to add something, I get 'EXC Bad Access" error message. When the program starts it checks for the file at that path, if not found it writes a blank plist file. I can look in the folder and I can see that it is created with this code
    Code:
    -(void)loadPrefsAtStart{
        skills = [[NSMutableDictionary alloc] init]; // Instansitates the NSMutableDictionary
        filemgr = [NSFileManager defaultManager];
        fileSavePath = [@"~/Documents/XPCalc.plist" stringByExpandingTildeInPath]; // Sets up the default path to the file.
        
        if ([filemgr fileExistsAtPath: fileSavePath ] == YES){
            skills = [[NSMutableDictionary alloc] initWithContentsOfFile: fileSavePath]; // it reads the file into the Dictionary
            for (NSString *i in skills) {         //  for loop to loop through the keys if the Dictionary and add to popUpButton
                [popUpButtonDisplay addItemWithTitle: i];
            }
        }
        else {
            [skills writeToFile: fileSavePath atomically:YES]; // if it can't find it, it writes a blank file.
        }
        
        [doaPrefField setStringValue:[ prefs stringForKey: @"doaPrefSave"]]; // reads in the NSUserDefault pref.
    }
    That code works fine and creates the file. When they add a new item to the list it should save it, but I get the error message on the last line of code bellow.

    Code:
    - (IBAction)addSkillPrefButton:(id)sender {
       [popUpButtonDisplay addItemWithTitle: [skillNamePref stringValue]]; // adds item to popUpbutton display
       [skills setObject:[skillBonusPrefField stringValue] forKey:[skillNamePref stringValue]]; // adds obj and key to the NSMutDict
       [skillNamePref setStringValue:@"-"]; //resets textfield
       [skillBonusPrefField setStringValue:@"-"]; //resets textfield
       [skills writeToFile: fileSavePath atomically: YES]; // saves the file by writing it to disk
        }
    I am lost because it writes it the first time to that location if the file does not exist so why could I not write over it with new data? Unless I need to append that file?
     
  8. balamw Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #8
    I haven't read the thread in detail so could be way off base, but often when this happens it's because the file is left open for read in another part of the code.

    B
     
  9. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #9
    I will look at that. I am also looking to see if I have some kind of memory management issue. I have never worked with the NSFileManager before I am not sure if I need to retain that object I create to keep writing or reading from that file.

    My gut says Memory Management.
     
  10. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #10
    balamw - I worked through the problem. You were right, about it being open. I made the mistake of putting this [filemgr release]; in the dealloc method. My thinking was that I would need to access the file all the time so keep it alive.

    I also need to add this code
    Code:
    filemgr = [NSFileManager defaultManager];
       fileSavePath = [@"~/Documents/XPCalc.plist" stringByExpandingTildeInPath]; // Sets up the default path to the file.
    To my addSkills button method. The help I got yesterday from Rob helped me better understand Memory Management and allowed me, with your hint , to fix the problem and see what is happening.

    Thanks!
     
  11. jiminaus, Jul 18, 2011
    Last edited: Jul 18, 2011

    jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #11
    The really kosher way to form you file save path is:
    Code:
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSAssert([paths count] > 0, @"Failed to find the user's document directory");
    NSString *documentsPath = [paths objectAtIndex:0];
    fileSavePath = [documentsPath stringByAppendingPathComponent:@"XPCalc.plist"];
    
     
  12. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #12
    That almost look confusing? Why would you put a pointer to a path inside of an NSArray? NSAssert, I have not seen that yet. This line I understand 'NSString *documentsPath = [paths objectAtIndex:0];' but why it is looking into the first index in an array I don't get. Why not store the path in an NSString? The last part I learned today and understand :)
     
  13. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #13
    It's possible for NSSearchPathForDirectoriesInDomains to return multiple paths, that's why it returns an array. It's unlikely in this case that NSSearchPathForDirectoriesInDomains will return more than one path, and it would be unclear what to do if it did return multiple paths, so the code just uses the first path.

    But happens if NSSearchPathForDirectoriesInDomains returns no paths at all, either returning nil or an empty array? The code assumes (or asserts) that this will not happen, so NSAssert checks for that.

    Basically NSAssert will evaluate the expression in the first parameter. If it is true, all is good, and the good continues. If it is false, then something is wrong, and NSAssert raises an exception containing the string in the second parameter.

    NSAssert is a good technique for defensive, fast-fail programming. You can read more about NSAssert in the Assertions and Logging Programming Guide.
     
  14. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #14
    The more I am getting into Objective-C and Cocoa I can see it is not a hobby for people. You really need to apply yourself and take it seriously if you are going to learn. I'm lucky because I work for myself and I can spend more time on this then most people. But wow, a lot to learn.

    Thanks, as always.
     
  15. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #15
    Programming is my hobby. But I've got almost a couple of decades of experience to back it up.

    Slowly slowly you'll get exposed to all the pieces.
     

Share This Page