iphone - writeToFile not saving new entry into plist - iphone

My writeToFile is not saving my data to my .plist.
- (IBAction)clickBtnDone:(id) sender {
NSLog(#"Done");
if ([txtGroupName.text length] > 0) {
[self dismissModalViewControllerAnimated:YES];
NSLog(#"Group Name: %#", txtGroupName.text);
NSMutableArray *newDict = [[NSMutableArray alloc] init];
[self.groups setObject:newDict forKey:txtGroupName.text];
NSLog(#"Count:%d", [self.groups count]);
BOOL success = [self.groups writeToFile:self.groupPath atomically:YES];
if(success) {
NSLog(#"Success Saving New Group");
} else {
NSLog(#"Failure Saving New Group");
}
[newDict release];
}
}
Here is what the debug shows:
2010-07-01 00:48:38.586 Contacts[7111:207] Done
2010-07-01 00:48:38.589 Contacts[7111:207] Group Name: C
2010-07-01 00:48:38.590 Contacts[7111:207] Count:3
2010-07-01 00:48:38.592 Contacts[7111:207] Success Saving New Group
However, when I open the .plist file, it still has only 2 groups that I had created manually, and not the new entry.
The files are located in my ~Documents folder.
Any ideas?

How you have initialized groupPath? It should be the path of document directory, not the path of resource directory.
You should do something similar :
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:FILE_NAME];
You can not edit the file that is present in the workspace.

NSString* plistPath = nil;
NSFileManager* manager = [NSFileManager defaultManager];
if ((plistPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"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];
}
}

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
}

Creating an array of dictionaries plist

I am creating a plist of dictionaries. The plist starts off as empty, and then I do this:
NSMutableArray *favouritesList = [[NSMutableArray alloc] initWithContentsOfFile:path];
[favouritesList addObject:thisPlace]; // where thisPlace is some NSDictionary
[favouritesList writeToFile:path atomically:YES];
When I immediately do:
NSArray *savedFav = [[NSArray alloc] initWithContentsOfFile:path];
NSLog(#"%#", savedFav);
I get an empty array. Why is this? Why isn't it writing properly? I am setting up the plist correctly, I debugged that. But I cannot add a dictionary to it.
The plist is just an empty plist with a root that's an array
EDIT:
Here is how I construct my path:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"favourites.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:path]) {
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"favourites" ofType:#"plist"];
[fileManager copyItemAtPath:sourcePath toPath:path error:nil];
}
I do something like below. I add an object using a key. Maybe that's why it's not working.
static NSMutableDictionary *dictionaryStore;
+(void)initialize{
if(dictionaryStore == nil){
dictionaryStore = [[NSMutableDictionary alloc] initWithContentsOfFile:[self getFilePath]];
if(dictionaryStore == nil)
dictionaryStore = [NSMutableDictionary new];
}
}
+(NSString *)getFilePath{
NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *plistPath = [rootPath stringByAppendingPathComponent:#"filename.plist"];
return plistPath;
}
+(NSString *)getValueForKey:(NSString *)key{
[self initialize];
return [dictionaryStore objectForKey:key];
}
+(void)setValue:(NSString *)value forKey:(NSString *)key{
[self initialize];
[dictionaryStore setValue:value forKey:key];
}
+(BOOL)save{
[self initialize];
return [dictionaryStore writeToFile:[self getFilePath] atomically:YES];
}
Edit:
So to save a value, I do:
[WAStore setValue:myValue forKey:myKey];
BOOL isSuccessful = [WAStore save];
WAStore is the class name. myValue can be most data types (NSManagedObjectModels won't work). myKey is any NSString.

how do we open an already existing database fmdb and where to include it?

I am using fmdb but i am not knowing where to add the db file.
I found this old answer that i think it doesn't fit for xcode 4.2 (since we dont have 'Resources' folder anymore).
I created a database in 'Lita', added the extension .sqlite and added the db file as follows :
then tried to use the following
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *path = [docsPath stringByAppendingPathComponent:#"db.sqlite"];
FMDatabase *database = [FMDatabase databaseWithPath:path];
[database open];
FMResultSet *results = [database executeQuery:#"select * from tbl"];
printf("hi");
while([results next]) {
printf("hi2");
NSString *name = [results stringForColumn:#"clm1"];
NSString *text = [results stringForColumn:#"clm2"];
NSLog(#"test: %# - %#",name, text);
}
printf("done");
i am getting the 'hi' 'done' but never 'hi2'...
anyone can help?
You want to add the (compiled) database to the project as a resource, and then copy it into the documents folder of the app on first start-up.
Here is an example method that does the work, call it from the applicationDidFinishLaunching and use the resultant FMDatabase * for all you queries.
- (FMDatabase *)openDatabase
{
NSFileManager *fm = [NSFileManager defaultManager];
NSString *documents_dir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *db_path = [documents_dir stringByAppendingPathComponent:[NSString stringWithFormat:#"database.s3db"]];
NSString *template_path = [[NSBundle mainBundle] pathForResource:#"template_db" ofType:#"s3db"];
if (![fm fileExistsAtPath:db_path])
[fm copyItemAtPath:template_path toPath:db_path error:nil];
FMDatabase *db = [FMDatabase databaseWithPath:db_path];
if (![db open])
NSLog(#"Failed to open database!");
return db;
}
I am working with the same issues right now. But to answer your question: the documents folder is the folder that is to be used in the device.
Put the database in the the supporting files folder.
Here is what works for me:
//hide status bar for full screen view
[[UIApplication sharedApplication]setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
//set reference to database here
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
self.databasePath = [documentDir stringByAppendingPathComponent:#"RPRA.sqlite"];
[self createAndCheckDatabase];
// Override point for customization after application launch.
return YES;
}
//method used to create database and check if it exists
-(void) createAndCheckDatabase
{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:self.databasePath];
if(success) return;
//else move database into documents folder
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:#"RPRA.db"];
[fileManager copyItemAtPath:databasePathFromApp toPath:self.databasePath error:nil];
}
- (void)ensureDBFile
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dbFilePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"retails.sqlite"]];
NSLog(#"Database Filepath Delgate = %#", dbFilePath);
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL dbFileExists = [fileManager fileExistsAtPath:dbFilePath];
if(!dbFileExists){
//Copy the db file if it didn't exist
NSString *bundledDbPath = [[NSBundle mainBundle] pathForResource:#"retails" ofType:#"sqlite"];
if (bundledDbPath != nil) {
BOOL copiedDbFile = [fileManager copyItemAtPath:bundledDbPath toPath:dbFilePath error:nil];
if (!copiedDbFile) {
NSLog(#"Error: Couldn't copy the db file from the bundle");
}
}
else {
NSLog(#"Error: Couldn't find the db file in the bundle");
}
}
self.db = [FMDatabase databaseWithPath:dbFilePath];
[self.db setShouldCacheStatements:NO];
[self.db open];
if([self.db hadError]) {
NSLog(#"Database Error %d: %#", [self.db lastErrorCode], [self.db lastErrorMessage]);
}
}

iPhone read/write .plist file

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"];

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)) {
// ...
}