iPhone read/write .plist file - iphone

I'm making a application where I need to store some information the user have provided. I try to use a .plist file to store the information, I found this:
NSString *filePath = #"/Users/Denis/Documents/Xcode/iPhone/MLBB/data.plist";
NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
[plistDict setValue:#"Man" forKey:#"Gender"];
[plistDict writeToFile:filePath atomically: YES];
The problem is that the application will only work as long as I'm testing it in the iPhone simulator. I've tried this Changing Data in a Plist but without luck. I have also read something about that I need to add it to my bundle, but how?
New code:
- (IBAction)segmentControlChanged{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistLocation = [documentsDirectory stringByAppendingPathComponent:#"data.plist"];
NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:plistLocation];
if (Gender.selectedSegmentIndex == 0) {
[plistDict setObject:#"Man" forKey:#"Gender"];
[plistDict writeToFile:plistLocation atomically: YES];
}
else
{
[plistDict setObject:#"Women" forKey:#"Gender"];
[plistDict writeToFile:plistLocation atomically: YES];
}
}

I guess you have added your plist file to your resources folder in Xcode (where we place image, if not then you need to place that first). Resources data goes to [NSBundle mainBundle] by default and iOS does not allow us to change data inside bundle. So first you need to copy that file to Documents Directory.
Here is the code for copying file from NSBundle to the Documents directory.
- (NSString *)copyFileToDocumentDirectory:(NSString *)fileName {
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *documentDirPath = [documentsDir
stringByAppendingPathComponent:fileName];
NSArray *file = [fileName componentsSeparatedByString:#"."];
NSString *filePath = [[NSBundle mainBundle]
pathForResource:[file objectAtIndex:0]
ofType:[file lastObject]];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL success = [fileManager fileExistsAtPath:documentDirPath];
if (!success) {
success = [fileManager copyItemAtPath:filePath
toPath:documentDirPath
error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable txt file file with message \
'%#'.", [error localizedDescription]);
}
}
return documentDirPath;
}
Now you can use the returned documentDirPath to access that file and manipulate (Read/Write) over that.
The plist structure is:
<array>
<dict>key-value data</dict>
<dict>key-value data</dict>
</array>
Here is code to write data into plist file:
/* Code to write into file */
- (void)addToMyPlist {
// set file manager object
NSFileManager *manager = [NSFileManager defaultManager];
// check if file exists
NSString *plistPath = [self copyFileToDocumentDirectory:
#"MyPlistFile.plist"];
BOOL isExist = [manager fileExistsAtPath:plistPath];
// BOOL done = NO;
if (!isExist) {
// NSLog(#"MyPlistFile.plist does not exist");
// done = [manager copyItemAtPath:file toPath:fileName error:&error];
}
// NSLog(#"done: %d",done);
// get data from plist file
NSMutableArray * plistArray = [[NSMutableArray alloc]
initWithContentsOfFile:plistPath];
// create dictionary using array data and bookmarkKeysArray keys
NSArray *keysArray = [[NSArray alloc] initWithObjects:#"StudentNo", nil];
NSArray *valuesArray = [[NSArray alloc] initWithObjects:
[NSString stringWithFormat:#"1234"], nil];
NSDictionary plistDict = [[NSDictionary alloc]
initWithObjects:valuesArray
forKeys:keysArray];
[plistArray insertObject:poDict atIndex:0];
// write data to plist file
//BOOL isWritten = [plistArray writeToFile:plistPath atomically:YES];
[plistArray writeToFile:plistPath atomically:YES];
plistArray = nil;
// check for status
// NSLog(#" \n written == %d",isWritten);
}

Are you using that same path on your device? Apps on a device are sandboxed and can only read/write files in their documents directory. Grab that file path like this and append your plist name. This approach will also work on the simulator.
Try this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistLocation = [documentsDirectory stringByAppendingPathComponent:#"myplist.plist"];

Related

Creating a plist if one doesn't exist

I've got a bit of code that imports settings into my app from an email, but it only works if the plist it imports the settings into already exists.
This is the code I'm using currently to import the settings and write to the plist.
-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
if (url){
NSDictionary *openedDictionary = [NSDictionary dictionaryWithContentsOfURL:url];
// get paths from root direcory
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
// get documents path
NSString *documentsPath = [paths objectAtIndex:0];
// get the path to our Data/plist file
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"Data.plist"];
NSDictionary *originalDictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath];
NSMutableDictionary *newDictionary = [originalDictionary mutableCopy];
for (NSString *key in openedDictionary) {
if (!newDictionary[key]) {
newDictionary[key] = openedDictionary[key];
}
}
[newDictionary writeToFile:plistPath atomically:YES];
}
NSError *error = nil;
if (![[NSFileManager defaultManager] removeItemAtURL:url error:&error]) {
NSLog(#"error while deleting: %#", [error localizedDescription]);
}
return YES;
}
But what I need to do is create that Data.plist if it's not there, or alternatively rename the plist that's emailed to Data.plist and store it provided there isn't already a Data.plist.
Here is how I would create the property list through code and retrieve data from it as well.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"plist.plist"]; NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
path = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat: #"plist.plist"] ];
}
NSFileManager *fileManager = [NSFileManager defaultManager];
NSMutableDictionary *data;
if ([fileManager fileExistsAtPath: path])
{
data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
}
else
{
// If the file doesn’t exist, create an empty dictionary
data = [[NSMutableDictionary alloc] init];
}
//To insert the data into the plist
int value = 5;
[data setObject:[NSNumber numberWithInt:value] forKey:#"value"];
[data writeToFile: path atomically:YES];
[data release];
// To retrieve the data from the plist
NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
int value1;
value1 = [[savedStock objectForKey:#"value"] intValue];
NSLog(#"%i",value1);
[savedStock release];
NSFileManager *defaultManager = [NSFileManager defaultManager];
if ([defaultManager fileExistsAtPath:plistPath])
{
// rename the file
}
else
{
//create empty file
}
this is how you can create empty plist file
NSDictionary *dict = [NSDictionary dictionary];
//you can create file in any path in app sandbox, for example I'm creating in document dir.
NSString *FilePathWithName = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
FilePathWithName = [FilePathWithName stringByAppendingPathComponent:#"name.plist"];
[dict writeToFile:FilePathWithName atomically:YES];
and for renaming what you can do is, you can load the .plist/.property file (that you want to rename) as dictionary and write that Dictionary with new name (write plist as above) and delete the .plist/.property file.
NSFileManager *defaultManager = [NSFileManager defaultManager];
if ([defaultManager fileExistsAtPath:plistPath]) {
//Do stuff with path
}
else {
//Write a plist to the path
}

unable to read/write data to .plist file in iPhone

i am new to iPhone developer, i am creating ePub reader for reading ePub files.
I have plist in my iphone app and I want to read and write data to my .plist file, in which i am facing problem.
here is my code snippet,
Logic: first i am downloading an ePub file, .ePub file will be downloaded to this path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSLog(#"basePath=%#",basePath);
output :-
=/Users/krunal/Library/Application Support/iPhone Simulator/5.1/Applications/6B7FCD58-EDF9-44F4-8B33-5F3542536F92/Documents
now, i want to write name of Downloaded .ePubfile into file into my .plist
code:
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: basePath];
[data setObject:[NSNumber numberWithInt:value] forKey:#"value"];
[data writeToFile: plistPath atomically:YES];
[data release];
i tried this, but i am unable to write in my .plist file.
Any Help Will be Appriciated.
Thanks In Advance !!
Did you mean:
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: plistPath];
?
untested code follows:
Step 1: Copy the file to it's folder.
NSError *error1;
BOOL resourcesAlreadyInDocumentsDirectory;
BOOL copied1;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath1 = [documentsDirectory stringByAppendingString:#"/epub.plist"];
resourcesAlreadyInDocumentsDirectory = [fileManager fileExistsAtPath:filePath1];
if(resourcesAlreadyInDocumentsDirectory == YES) {
} else {
NSString *path1 = [[[NSBundle mainBundle] resourcePath] stringByAppendingFormat:#"/epub.plist"];
copied1 = [fileManager copyItemAtPath:path1 toPath:filePath1 error:&error1];
if (!copied1) {
NSAssert1(0, #"Failed to copy epub.plist. Error %#", [error1 localizedDescription]);
}
}
Step 2:Open it
NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath1];
Step 3:Write data to it
[dict setObject:[NSNumber numberWithInt:value] forKey:#"value"];
[dict writeToFile:path atomically:YES];
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: basePath];
data is nil here, you should init it with:
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
Edited my answer to be more clear:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
if ( basePath == nil ) {
return
}
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
[data setObject:[NSNumber numberWithInt:value] forKey:#"value"];
NSString *plistPath = [NSString stringWithFormat:#"%#/name.plist", basePath];
[data writeToFile: plistPath atomically:YES];
[data release];
It is easer for you to use NSUserDefault, you data will be saved to a plist file as following code:
- (void)setOverviewGroupInstrument:(BOOL)isGroupded {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:[Your array] forKey:[Your Key]];
[prefs synchronize];
}
Then you can read by:
- (NSMutableArray*)getOverviewInstrumentList {
return [prefs objectForKey:[Your Key]];
}

How to Save NSMutableArray into plist in iphone

I am new in iphone, i want to save NSMutableArray data into plist file my Code is:
NSArray *array = [[NSArray alloc] initWithArray:self.artistDetailsArray];
[self.artistDetailsArray writeToFile:self.path atomically:YES];
but it shows 0 element in my plist path. please any help me.
Thanks in advance:
following is my code to store the data into plist and NSUserDefault.
none of them is working for NSMutableArray/NSArray but working for NSString. IS there any max size limit to store in plist or UserDefault??
NSMutableArray contains only text/ set of NSDictionary.
please suggest me.
- (void)initialiseDataFromLocalStorage
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
self.path = [documentsDirectory stringByAppendingPathComponent:#"saveLogin.plist"];
if ([fileManager fileExistsAtPath:self.path] == NO) {
NSString *pathToDefaultPlist = [[NSBundle mainBundle] pathForResource:#"saveLogin" ofType:#"plist"];
if ([fileManager copyItemAtPath:pathToDefaultPlist toPath:self.path error:&error] == NO) {
NSAssert1(0,#"Failed with error '%#'.", [error localizedDescription]);
}
}
// To get stored value from .plist
NSDictionary *dict = [[NSDictionary alloc]initWithContentsOfFile:self.path];
self.ResumedataDictionary = [[NSMutableDictionary alloc]initWithDictionary:dict];
[dict release];
self.artistDetailsArray = [[NSMutableArray alloc] initWithArray:[self.ResumedataDictionary objectForKey:#"artistDetailsDict"]];
// To get stored value from NSUserDefault
NSUserDefaults *fetchData = [NSUserDefaults standardUserDefaults];
self.artistDetailsArray = [fetchData objectForKey:#"artistDetailsDict"];
}
-(void)saveDataToLocalStorage
{
// To store value into .plist
NSArray *array = [[NSArray alloc] initWithArray:self.artistDetailsArray];
[ResumedataDictionary setObject:array forKey:#"artistDetailsDict"];
[ResumedataDictionary writeToFile:self.path atomically:YES];
// To store value into NSUserDefault
NSUserDefaults *fetchData = [NSUserDefaults standardUserDefaults];
[fetchData setObject:self.artistDetailsArray forKey:#"artistDetailsDict"];
}
NSMutableArray *array=[[NSMutableArray alloc] init];
[array addObject:#"test"];
[array writeToFile:#"/Users/parag/test.plist" atomically:YES];
[array release];
or
NSMutableArray *array=[[NSMutableArray alloc] init];
[array addObject:#"test121"];
id plist = [NSPropertyListSerialization dataFromPropertyList:(id)array format:NSPropertyListXMLFormat_v1_0 errorDescription:#error];
[plist writeToFile:#"/Users/parag/test.plist" atomically:YES];
Take a look at Creating Property Lists Programmatically
look at this code which creates path to plist in documents directory:
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
NSString *documentsDirectory = [paths objectAtIndex:0]; //2
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"data.plist"]; //3
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path]) //4
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#”data” ofType:#”plist”]; //5
[fileManager copyItemAtPath:bundle toPath: path error:&error]; //6
}
1) Create a list of paths.
2) Get a path to your documents directory from the list.
3) Create a full file path.
4) Check if file exists.
5) Get a path to your plist created before in bundle directory (by Xcode).
6) Copy this plist to your documents directory.
next read data:
NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
//load from savedStock example int value
int value;
value = [[savedStock objectForKey:#"value"] intValue];
[savedStock release];
write data:
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
//here add elements to data file and write data to file
int value = 5;
[data setObject:[NSNumber numberWithInt:value] forKey:#”value”];
[data writeToFile: path atomically:YES];
[data release]
You can use property lists (NSPropertyListSerialization or writeToFile: way).
But be sure your array contains valid property list objects only (NSString, NSNumber, NSData, NSArray, or NSDictionary objects) and NSDictionary has only NSString keys. Custom (complex) objects have to be represented as dictionaries.
Or you should use approach with archives http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Archiving/Archiving.html through NSCoding protocol.
Nice guide is here http://cocoadevcentral.com/articles/000084.php
NSData *serializedData;
NSString *error;
serializedData = [NSPropertyListSerialization dataFromPropertyList:YourArray(You can use dictionaries.strings..and others too)
format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
if (serializedData) {
// Serialization was successful, write the data to the file system // Get an array of paths.
NSArray *documentDirectoryPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [NSString stringWithFormat:#”%#/serialized.xml”,
[documentDirectoryPath objectAtIndex:0]];
[serializedData writeToFile:docDir atomically:YES];
}
else {
// An error has occurred, log it
NSLog(#”Error: %#”,error); }
}

How can I overwrite the contents of a plist file? (iPhone / iPad)

I have a plist file in my main app bundle that I want to update via my app. Here is the code I'm using, the problem is that the plist doesn't seem to be getting updated. Is my code incorrect or is there another issue?
// Data
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
[data setObject:self.someValue forKey:#"Root"];
// Save the logs
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"MyFile" ofType:#"plist"];
[data writeToFile:filepath atomically:YES];
Please can someone help me out?
IOS restricts writing to bundled files. If you want a writable plist, you need to copy it to your app's Documents folder and write to it there.
Here's how I'm doing it in one of my apps
//get file paths
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
NSString *documentPlistPath = [documentsDirectory stringByAppendingPathComponent:#"document.plist"];
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *bundlePlistPath = [bundlePath stringByAppendingPathComponent:#"bundle.plist"];
//if file exists in the documents directory, get it
if([fileManager fileExistsAtPath:documentPlistPath]){
NSMutableDictionary *documentDict = [NSMutableDictionary dictionaryWithContentsOfFile:documentPlistPath];
return documentDict;
}
//if file does not exist, create it from existing plist
else {
NSError *error;
BOOL success = [fileManager copyItemAtPath:bundlePlistPath toPath:documentPlistPath error:&error];
if (success) {
NSMutableDictionary *documentDict = [NSMutableDictionary dictionaryWithContentsOfFile:documentPlistPath];
return documentDict;
}
return nil;
}
Hope this helps

check if plist exist, if not load from here

I am trying to check whether a plist exists in my doc folder: if yes, load it, if not load from resource folder.
- (void)viewWillAppear:(BOOL)animated
{
//to load downloaded file
NSArray *docpaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [docpaths objectAtIndex:0];
NSString *docpath = [documentsDirectory stringByAppendingPathComponent:#"downloadedfile.plist"];
//if document folder got file
if(docpath != nil)
{
NSDictionary *dict = [[NSDictionary alloc]
initWithContentsOfFile:docpath];
self.allNames = dict;
[dict release];
}
//on error it will try to read from disk
else {
NSString *path = [[NSBundle mainBundle] pathForResource:#"resourcefile"
ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc]
initWithContentsOfFile:path];
self.allNames = dict;
[dict release];
}
[table reloadData];
Where did I go wrong? The plist is not loading from resource folder.
I think if you create an instance of NSFileManager you can then use the file exists method
BOOL exists;
NSFileManager *fileManager = [NSFileManager defaultManager];
exists = [fileManager fileExistsAtPath:docPath];
if(exists == NO)
{
// do your thing
}
You need to check wether the file exists in your Documents folder (with NSFileManager or something like this). stringByAppendingPathComponent: doesn’t care wether the path it returns exists or is valid.
I have used a similar approach in one of the applications and it was working fine for me. Where at the launch of the application, I check for the plist file inside the document directory and if it does not exists there, then it is copied from the resource folder.
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSString * plistName = #"FlowerList";
NSString * finalPath = [basePath stringByAppendingPathComponent:
[NSString stringWithFormat: #"%#.plist", plistName]];
NSFileManager * fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:finalPath])
{
NSError *error;
NSString * sourcePath = [[NSBundle mainBundle] pathForResource:#"FlowerList" ofType:#"plist"];
[fileManager copyItemAtPath:sourcePath toPath:finalPath error:&error];
}
Here is the Swift version of Chris's Answer:
if (NSFileManager.defaultManager().fileExistsAtPath(path)) {
// ...
}