Editing plist file(objective c) - objective-c

I'm new to Objective C, and currently working on an iphone app. My app needs to take user inputs(strings) and store them, so I am using plist to store the data. Currently, I can read from the plist file. However, when I tried to write to the plist file, the file itself does not change at all.
What I'm trying to do is to append user's input to the existing plist file. So I read the plist file and store the array to a mutableArray. Then, I use the addObject function to append the new user input at the end of the mutableArray. Till this point, everything is working fine, and the mutableArray is exactly how I wanted it. The last step is what's not working for me:
[mutableArray writeToFile:[self dataFilePath] atomically:YES];
I assume that the my plist file(located in my resource folder along with the .h and .m files) should be changed after this line is executed and the new user input should be appended, but the file doesn't seem to change at all.
I have read some people say that I should copy the plist file from NSBundle to the Documents directory because the plist file is in the resource folder, but among almost all the tutorials on youtube, there has not been a problem like that and their code still work fine with their plist file in the resource folder.
Thank you in advance for your help.

Yes you must copy file from NSBundle to NSDocumentUser for example file "NimrokhRavanshenasi.sqlite3"
NSFileManager* fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDbtPath = [documentsDirectory stringByAppendingPathComponent:#"NimrokhRavanshenasi.sqlite3"];
BOOL success = [fileManager fileExistsAtPath:writableDbtPath];
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"NimrokhRavanshenasi.sqlite3"];
NSError *error;
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDbtPath error:&error];
NSFileManager *filemgr = [NSFileManager defaultManager];
sqlite3_stmt *compiledStatement;
if([filemgr fileExistsAtPath:writableDbtPath]){
if (sqlite3_open([writableDbtPath UTF8String], &_contactDB) != SQLITE_OK) {
NSLog(#"Failed to open database!");

Related

sqlite connection with Objective C

I have a simple piece of code where I connect my sqliteDb.
My sqlite3_prepare_v2 though repeatedly fails. I narrowed it down to the following piece of code:
NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:#"xyz" ofType:#"sqlite3"];
sqLiteDb returns null. I don't know why - tried everything I could and followed many threads.
Really struggling here - please help.
Are you sure your xyz.sqlite3 file is included in the correct Target Membership? If it is not included, then it will not be copied to your bundle when building.
Try this
in.h file
NSString *databasePath;
in .m file
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:#"dbname.sqlite"];
[self checkAndCreateDatabase];
-(void) checkAndCreateDatabase
{
// Check if the SQL database has already been saved to the users phone, if not then copy it over
BOOL success;
// Create a FileManager object, we will use this to check the status
// of the database and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
success = [fileManager fileExistsAtPath:databasePath];
// If the database already exists then return without doing anything
if(success) return;
// If not then proceed to copy the database from the application to the users filesystem
// Get the path to the database in the application package
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}

Merge old Plist with new Plist

I have add new entities to existing Plist. New version of app crashes due to Plist inconsistencies.
How do I merge old plist data with new plist?
My Plist creation method is as follows
- (void)createEditableCopyOfFileIfNeeded:(NSString *)plistName
{
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:plistName];
success = [fileManager fileExistsAtPath:plistPath];
if (success)
{
return;
}
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:plistName];
success = [fileManager copyItemAtPath:defaultPath toPath:plistPath error:&error];
if (!success)
{
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
Thanks in advance
I would include a version key in your plist to compare it with the version of the application. You can check the version of your application with the following snippet:
[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleVersion"]
Then, at the startup of the application:
Read the plist, if there is no version key, it will be old version.
If old version then perform data migration to current version, adding the non-existing keys with default values. Here I would take in account different version numbers for future updates.
Add the version key with the version of your bundle as a value.
Save the plist.
You can do it this way:
Rename old plist e.g. old.plist
Read both plists from separate files
Merge information needed adding chosen information programatically to new plist
Save new plist merged

Unable to copy file from bundle to Documents directory, why does fileExistsAtPath return error?

I'm using the following snippet of code to attempt to copy a file from my application resources directory into the Documents area. I have used the below from the PocketOCR project on Github :
// Set up the tessdata path. This is included in the application bundle
// but is copied to the Documents directory on the first run.
NSString *dataPath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:#"tessdata"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSLog(#"Datapath is %#", dataPath);
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:dataPath ]) {
NSLog(#"File didn't exist at datapath...");
// get the path to the app bundle (with the tessdata dir)
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *tessdataPath = [bundlePath stringByAppendingPathComponent:#"tessdata"];
if (tessdataPath) {
[fileManager copyItemAtPath:tessdataPath toPath:dataPath error:NULL];
}
}
This is the output I get from invoking the above :
2012-06-06 14:53:42.607 MyApp[1072:707] Datapath is
/var/mobile/Applications/9676D920-D6D1-4F86-9177-07CC3247A124/Documents/tessdata
Error opening data file
/var/mobile/Applications/9676D920-D6D1-4F86-9177-07CC3247A124/Documents/tessdata/eng.traineddata
I have the eng.traineddata file located in my xcode project like so
It appears that the Error is being reported when attempting to check if fileExistsAtPath, I wouldn't expect this to throw an error, but to either return YES or NO.
Is there an easier way to copy the eng.traineddata file across, or have I made a mistake which can be corrected here?
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSString *dataPath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:#"tessdata"];
NSLog(#"Datapath is %#", dataPath);
// If the expected store doesn't exist, copy the default store.
if ([fileManager fileExistsAtPath:dataPath] == NO)
{
NSString *tessdataPath = [[NSBundle mainBundle] pathForResource:#"eng" ofType:#"traineddata"];
[fileManager copyItemAtPath:tessdataPath toPath:dataPath error:&error];
}
-(NSString*) applicationDocumentsDirectory{
// Get the documents directory
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
return docsDir;
}
I hope also help this code to copy all type of file bundle to Document directory folder ..
NSString *pathsToReources = [[NSBundle mainBundle] resourcePath];
NSString *yourOriginalDatabasePath = [pathsToReources stringByAppendingPathComponent:#"lunchDB.sqlite"]; // file name u want copy
NSArray *pathsToDocuments = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [pathsToDocuments objectAtIndex: 0];
NSString *dbPath = [documentsDirectory stringByAppendingPathComponent:#"lunchDB.sqlite"]; // file name & your original path (Document path)
if (![[NSFileManager defaultManager] isReadableFileAtPath: dbPath]) {
if ([[NSFileManager defaultManager] copyItemAtPath: yourOriginalDatabasePath toPath: dbPath error: NULL] != YES)
NSAssert2(0, #"Fail to copy database from %# to %#", yourOriginalDatabasePath, dbPath);
}
Thanks ..
Use the method fileExistsAtPath:isDirectory: of NSFileManager and specify that the path is a directory, because it is.
stringByAppendingPathComponent:#"tessdata"
The line above required that tessdata is a physical folder (a blue color folder), not a group (yellow folder as you are showing) in Xcode project. Create a folder in your Xcode project folder using the Finder and then in Xcode drag and drop the folder to your project and select the folder reference when asked.

where does the text file I dragged to xcode go on the iphone/simulator?

I have some data in a .txt file that I dragged over to resources in xcode 4.2. I then use some methods that call upon this file, read it, and display it on the screen to the user. It works. My problem is writing to the end of the same file (aka updating the file based on something the user did) directly on the iphone/ the simulator. It does not write for I feel I am not calling upon the right location and perhaps method. This is my code to write to the end of file, if anyone knows why this is not working it would be tremendous help.
Thank you
-(void)updateFile:(id)sender
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//append filename to docs directory
NSString *myPath = [documentsDirectory stringByAppendingPathComponent:#"Mom.txt"];
fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:myPath];
dateCombinedString= [dateCombinedString lowercaseString];
writtenString= [[NSString alloc]initWithFormat:#", %#, %#, %#",dateString,trimmedString,ForDisplay];
[fileHandle seekToEndOfFile];
[fileHandle writeData:[writtenString dataUsingEncoding:NSUTF8StringEncoding]];
[writtenString release]
}
The file you dragged to Xcode is inside your app resources. You can get the path to resource with this line of code:
NSURL* fileUrl = [[NSBundle mainBundle] URLForResource:#"Mom" withExtension:#"txt"];
However, you cannot modify the files in the resource directory therefore you should first copy that file to your document directory, then modify it with the code in the question.
Here is how you can copy file from resources if the file does not exist on the documents folder:
NSFileManager* fm;
fm = [NSFileManager defaultManager];
//only copy it from resources if it does not exits
if(![fm fileExistsAtPath:myPath]){
NSURL* myUrl = [NSURL fileURLWithPath:myPath];;
NSError* error = nil;
[fm copyItemAtURL:fileUrl toURL:myUrl error:&error];
//handle the error appropriately
}

Reading data from a file

I'm new to mac and Cocoa so I'm sorry if this is a stupid question..
I need to read all the lines I wrote on a file I saved on my desktop.
The file format is .txt; I tried with stringWithContentsOfFile but the program freezes.
I tried with GDB and I noticed that, while the path is correct, the string which is supposed to contain the data returns nil.
Am I missing something important?
You need to use a path not just the filename
NSString *string;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
if ([paths count] != 0) {
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *newFile = [documentsDirectory stringByAppendingPathComponent:#"filename.txt"];
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:newFile]) {
string = [NSString stringWithContentsOfFile:newFile];
}
}
You will need to replace the documents directory for the bundle directory if you are reading from there.
EDIT
I jumped the gun. It seems that this is NOT an iPhone question. None-the-less, you will need to pass in the full path, not just the filename