How to write data in plist?

I have created save.plist in a resource folder. I have written some data within that directly (without using coding). I am able to read that data but I'm not able to write through code to the same save.plist. By using following code I am trying to write the data but it gets stored within my .app plist. The code is here

NSString *errorDesc = nil;

NSPropertyListFormat format;

NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"save" ofType:@"plist"];

NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];

NSMutableDictionary *temp = (NSMutableDictionary *)[NSPropertyListSerialization
                     propertyListFromData:plistXML
                              mutabilityOption:NSPropertyListMutableContainersAndLeaves
                  format:&format errorDescription:&errorDesc];

if (!temp) {

    NSLog(errorDesc);

    [errorDesc release];        
    }
    //  [temp setValue:@"123" forKey:@"line1"];
    //  [temp writeToFile:plistPath atomically: YES];

    //Reading data from save.plist
    NSLog([temp objectForKey:@"name"]);
    NSLog([temp objectForKey:@"wish"]);
    NSNumber *num=[temp valueForKey:@"roll"];
    int i=[num intValue];
    printf("%d",i);
        //writitng the data in save.plist

    [temp setValue:@"green" forKey:@"color"];
    [temp writeToFile:plistPath atomically: NO];
    NSMutableDictionary *temp1 = (NSMutableDictionary *)[NSPropertyListSerialization
                propertyListFromData:plistXML                                                            
                                mutabilityOption:NSPropertyListMutableContainersAndLeaves
                format:&format errorDescription:&errorDesc];

    NSLog([temp objectForKey:@"color"]);

I want that, the data which I want to write should get written into save.plist only which is stored in references. I am new with this concept. So if anyone knows it please help me. Thanks in advance. :-)


I don't know if I understand your question, but if you want to write into a .plist within your .app bundle you are probably doing something wrong. If you want to store preferences, you should consider using NSUserDefaults.
If you really want to modify a bundled .plist - here is some code:

NSString *plistPath = nil;
NSFileManager *manager = [NSFileManager defaultManager];
if (plistPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents/Info.plist"]) 
{
    if ([manager isWritableFileAtPath:plistPath]) 
    {
        NSMutableDictionary *infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
        [infoDict setObject:[NSNumber numberWithBool:hidden] forKey:@"LSUIElement"];
        [infoDict writeToFile:plistPath atomically:NO];
        [manager changeFileAttributes:[NSDictionary dictionaryWithObject:[NSDate date] forKey:NSFileModificationDate] atPath: [[NSBundle mainBundle] bundlePath]];
    }
}

Update:
Nate Flink pointed out that some of the NSFileManager methods used above are deprecated. He posted an answer with the replacement methods below: https://stackoverflow.com/a/12428472/100848


Updated version of the original awesome example by weichsel (thank you!). Xcode threw a couple warnings one of which is a deprecated method on NSFileManager. Updated here with non-deprecated methods from iOS 5.1

    NSString *plistPath = nil;
NSFileManager *manager = [NSFileManager defaultManager];
if ((plistPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"mySpecial/PathTo.plist"])) 
{
    if ([manager isWritableFileAtPath:plistPath]) 
    {
        NSMutableDictionary *infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
        [infoDict setObject:@"foo object" forKey:@"fookey"];
        [infoDict writeToFile:plistPath atomically:NO];
        [manager setAttributes:[NSDictionary dictionaryWithObject:[NSDate date] forKey:NSFileModificationDate] ofItemAtPath:[[NSBundle mainBundle] bundlePath] error:nil];
    }
}

When you build the app, it will create an executable file "appName.app" and all the files are built in the bundle. Therefore, you can't access to resource folder when the app is running because all the data is in the bundle(not in folder).

However, you can access to a temp folder which contains some information of the app. You can find the temp folder here: Open finder--click on your username(under PLACES)--Library--Application Support--iPhone Simulator--User--Applications--(here you can find all the temp folders of your iPhone apps)

You can access to this temp folder by:


NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

If you name your file save.plist, you can access to it like this:

NSString *filePath = [documentsDirectory stringByAppendingString:@"_save.plist"];

Then you just save your file to this filePath and it will appear in the temp folder named "Documents_save.plist".

*Note that the temp folder's name varies every time you run the app.

Recommend a book for you: 《Beginning iPhone Development--Exploring the iPhone SDK》. In Chapter 11 you can find what you want.


To summarize some of the other answers:

You're problem is that you're trying to write the file back into the folder that contains your application. That folder is not writable at runtime. Everything you're doing is fine, you just need to pick a different location to write your file to.

You can use the NSSearchPathForDirectoriesInDomains function to find a more suitable folder for this data. (Such as the @"Documents" folder.)


try this:

-(void)add:(NSRunningApplication *) app { 
   if ([self contains:app]) return; 
   [self.apps addObject:app.localizedName]; 
   [self.apps writeToFile:self.dataFile atomically:YES];
}

from "Cocoa Programming".