Write to Plist file, but dont replace it - objective-c

Im creating a application that writes strings to a plist file, but the problem im having is every time its writing to the plist file, it deletes the previous one, im trying to figure out either how to write to the existing one without deleting its original contents, or replace the plist file and keep the original contents and then re write them on to it..
Heres what my code looks like to save the file
- (NSString *) saveFilePath
{
NSArray *pathArray =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[pathArray objectAtIndex:0] stringByAppendingPathComponent:#"scores.plist"];
}
-(void)alertView:(UIAlertView *)alert_view didDismissWithButtonIndex:
(NSInteger)button_index{
if(button_index == 0){
NSLog(#"1");
score = 0;
}
if(button_index == 1){
NSLog(#"2");
NSString *scoreString = [NSString stringWithFormat:#"%i by %#", score, name.text];
NSLog(#"%#", scoreString);
NSArray *values = [[NSArray alloc] initWithObjects:scoreString, nil];
[values writeToFile:[self saveFilePath] atomically:YES];
[values release];
score = 0;
}
}
Any ideas? Thanks!

You can read the plist and write it to the NSMutableArray. Then append it with your data and write it back to the file overwriting the existing one.
The same thing with NSMutableDictionary.

Related

Read from file.Plist Returns Null

Program that Creates multiple Plist's Paths for Different information.
But only one path is not working.
(i think "writeToFile" is the problem)
code:
-(NSString *) createPath:(NSString *)withFileName
{
NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,
YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:withFileName];
return path;
}
Path
NSLog = /var/mobile/Applications/02CABC0A-6B5B-4097-A9D1-4336BE8230B7/Documents/MessagesDB.plist
&
-(void) messagesDbFlush
{
// save it to the file for persistency
NSString *messagesDB_Path = [self createPath:_fileMessagesDB];
[_messagesDB writeToFile:messagesDB_Path atomically:YES];
NSMutableArray *ReturnsInfo = [[NSMutableArray alloc ]initWithContentsOfFile:messagesDB_Path];
NSLog(#"ReturnsInfo is : %#", ReturnsInfo);
}
"ReturnsInfo" Array is Null :/
Anyone please help?
I once had the same error.
1) Check the name of the plist in the directory listing to match your coded one
2) Check Project settings, manually delete the pre-existing plist from the "Build Settings" > "Copy Bundle Resources", and drag drop from the list.
3) Select the plist in directory listing, check Utilities sidebar, check Identity & Type > Location as valid
4) If you deleted the app's "default" plist aka bundle identifier, add copy build phase, choose destination, choose pref folder as absolut path check "copy only when installing"
This solved my returning null.
And if all fails on the bundle identifier, you can always copy the plist to pref folder by code:
NSString *path = [#"~/Library/Preferences/com.MyCompany.MyApp.plist" stringByExpandingTildeInPath];
BOOL PrefsExist=[[NSFileManager defaultManager] fileExistsAtPath:path];
NSString *copyPrefsPath = [#"~/Library/Preferences/com.MyCompany.MyApp.plist" stringByExpandingTildeInPath];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (PrefsExist == 0)
{
// Copy the plist to prefs folder (one-time event)
NSString *tessdataPath = [[NSBundle mainBundle] pathForResource:#"com.MyCompany.MyApp" ofType:#"plist"];
[fileManager copyItemAtPath:tessdataPath toPath:path error:&error];
} else
{
// Read/Write the values from plist
}
i have stored following array with 5 objects in it, its working fine on my side, try it
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:5];
for(int i=0;i<5;i++)
[array addObject:#"This is Demo String, You can write your own String here"];
NSString *_fileMessagesDB = #"MessagesDB.plist";
// save it to the file for persistency
NSString *messagesDB_Path = [self createPath:_fileMessagesDB];
[array writeToFile:messagesDB_Path atomically:YES];
NSMutableArray *ReturnsInfo = [[NSMutableArray alloc ]initWithContentsOfFile:messagesDB_Path];
NSLog(#"ReturnsInfo is : %#", ReturnsInfo);

How to write data in .plist?

I'm trying to save some comments in a plist, that's OK cause its just a prototype. The problem is that i can read from plist but when I try to write and read after that, it throws an "array out of bounds" exception. I can't figure it out what I'm doing wrong here.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Comments" ofType:#"plist"];
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
NSMutableDictionary *newComment = [NSMutableDictionary dictionary];
[newComment setValue:commentTitle.text forKey:#"title"];
[newComment setValue:comment forKey:#"comment"];
[plistArray addObject:newComment];
[plistArray writeToFile:filePath atomically:NO];
That works fine, then i try to read:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Comments" ofType:#"plist"];
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
NSMutableDictionary *dictionary = (NSMutableDictionary *) [plistArray objectAtIndex:0];
NSLog(#"%#", [dictionary objectForKey:#"title"]);
And it throws the exception.
If I add the item manually to the plist, it works fine, i guess it means that my reading code its fine.
Could it be the structure of my plist?
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
</array>
</plist>
* Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (1) beyond bounds (1)'
I added the "description" to the array before writing to the plist. If i use the following code:
NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// NSString *aFilePath = [NSString stringWithFormat:#"%#/Comments.plist", aDocumentsDirectory];
//
// NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:aFilePath];
The return is (null)
But if i use:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Comments" ofType:#"plist"];
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
i can see the contents of the array, and its all working properly.
The problem is: In both ways i cant write to the file, it keeps returning "NO". And i already checked the permissions
You are trying to write the file into mainBundle. Definitely not possible.
You will have to write the plist file to Documents or Application Support folder of the app.
Create File Path in Documents Directory :
NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *aFilePath = [NSString stringWithFormat:#"%#/Comments.plist", aDocumentsDirectory];
Write to FilePath
[plistArray writeToFile:aFilePath atomically:YES];
Read From FilePath
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:aFilePath];
I see two problems with your code:
(May or may not be a problem). If the file does not exist initially, the initWithContentsOfFile: selector will return nil, causing the rest of your code to be no-ops.
(Probably the cause). You may not write to the bundle resources directory. Store your file in the Documents or Caches directory instead.
To locate your documents directory, use something like this:
- (NSString*) pathForDocument:(NSString*)documentName {
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
if(documentDirectories.count < 1) return nil;
return [[documentDirectories objectAtIndex:0] stringByAppendingPathComponent:documentName];
}
First of all, why are you writing a file into your bundle?
Then, to address your problem, check if you actually did write the file.
if ([plistArray writeToFile:filePath atomically:NO])
NSLog (#"Written");
else
NSLog (#"Not Written");
Also, log your array when you're read it using -(void)description to check the contents of the dictionary.
Edit
As you said that you're not writing to your plist. For now, just create a test plist on your desktop.
NSString *testPath = [[NSString stringWithString:#"~/Desktop/Comments.plist"] stringByExpandingTildeInPath];
if ([plistArray writeToFile:testPath atomically:NO])
NSLog (#"Written");
else
NSLog (#"Not Written");
If that still returns Not Written, then there's something wrong with your dictionary. Which I doubt because it's just strings (Though they could be placeholders for asking your question on stackoverflow. The docs states that the classes in the dictionary must be of NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary). If that says written though, I'm guessing it doesn't write to your bundle because of permissions, which then you have to change your plist location to somewhere else other than your bundle, which I highly recommend.
If you only put one item in the array, you should obviously use index 0 instead of 1 when reading from it:
NSMutableDictionary *dictionary = (NSMutableDictionary *) [plistArray objectAtIndex:0];

NSMutableArray always return null

My problem is when I read content of plist file in an NSMutableArray always return null
NSString *resourceDocPath = [[NSString alloc] initWithString:[[NSBundle mainBundle]bundlePath]] ;
// Create the new dictionary that will be inserted into the plist.
NSMutableDictionary *nameDictionary = [NSMutableDictionary dictionary];
[nameDictionary setValue:#"walid" forKey:#"id"];
[nameDictionary setValue:#"555 W 1st St" forKey:#"lien"];
NSString *r = [NSString stringWithFormat:#"%#/download.plist", resourceDocPath];
NSLog(#"%#",r);
// Open the plist from the filesystem.
NSMutableArray *plist = [NSMutableArray arrayWithContentsOfFile:r];
NSLog(#"%#",plist);
if (plist == NULL)
{
plist = [NSMutableArray array];
}
[plist addObject:nameDictionary];
NSLog(#"%#",plist);
[plist writeToFile:r atomically:YES];
when I look in the plist file I found the data that I insert only one
can you help me please?
You're trying to access the application bundle rather than the documents directory, which can be accessed via NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Populator"];. The bundle cannot be modified, so the created array is never saved, hence why it is never loaded.
First you should not check for plist == null but check for plist == nil
Second searching for the download file should be changed into the following:
NSURL *url = [[NSBundle mainBundle] URLForResource:#"download" withExtension:#"plist"];
NSMutableArray *plist = [NSMutableArray arrayWithContentsOfURL:url];
Third:
I do not think a file with the extension of plist will return an Array.
It will probably represent an dictionary. Try creating an NSMutableDictionary instead of an array.

Need help to quickly search iOS Property List (plist) for value?

I currently have a plist file in my iOS Project which is downloaded from the web when updates are available and it contains a list of news articles along with images.
The application caches the images on the iPhone for offline access, I am currently trying to write a function which will clean the cached files every so often.
Currently I have this code which looks in the Temp folder for images and then deletes them, however for each image found I would like it to check if the file name exists as a value in the plist stored as NSDictionary before deleting, however I am not sure of a quick method to search the NSDictionary without the need for a for statement.
Any tips would be great.
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:TMP error:nil];
if (files == nil) {
// error...
NSLog(#"no files found");
}
for (NSString *file in files) {
NSString *uniquePath = [TMP stringByAppendingPathComponent: file];
if([file rangeOfString: #".png" options: NSCaseInsensitiveSearch].location != NSNotFound)
{
NSLog(#"%#", file);
if ([[NSFileManager defaultManager] removeItemAtPath: uniquePath error: NULL] == YES)
NSLog (#"Remove successful");
else
NSLog (#"Remove failed");
}
}
EDIT
I have currently added this not sure if its the best way to do it but it works.
NSArray *newsArray = [self.newsData allValues];
// Convert the Array into a string
NSString *newsString = [newsArray description];
// Perform Range Search.
NSRange range;
range = [newsString rangeOfString : filename];
if (range.location != NSNotFound) {
NSLog(#"The file exists in the plist %#", filename);
} else {
// Delete the file
}
You could reduce the array so that it only contains the objects you are interested in by using a NSPredicate, then quickly loop over the objects which you wish to delete. Like so:
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:TMP error:nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF CONTAINS[cd] '.png'"];
NSArray *filteredArray = [files filteredArrayUsingPredicate:thePredicate];
for (NSString *file in filteredArray) {
NSString *uniquePath = [TMP stringByAppendingPathComponent:file];
if ([[NSFileManager defaultManager] removeItemAtPath: uniquePath error: NULL])
NSLog (#"Remove successful");
else
NSLog (#"Remove failed");
}
This will mean that the for loop is only looping over objects you are interested in.
Since you do not care about the sequence of files in plist or folder and you obviously won't have duplication, use NSSet rather than NSArray and then use intersect method (intersectsSet:) to find intersection.

How can Add new line in plist

Hi friends i'm beginner
and sorry for simple Questions.
how can i add new lines in ""plist"" for saving data
and access keys in it.
NSArray *values = [[NSArray alloc] initWithObjects:#"Hello",nil];
[values writeToFile:[self PathArray] atomically:YES];
because , this method Only overwrite Values in ([self PathArray]) "path";
Thanks
Plist files are not designed for incremental updates, instead you should load plist contents in memory, add an item to it and save back:
NSMutableArray *oldValues = [NSMutableArray arrayWithContentsOfFile:[self PathArray]];
NSArray *values = [[NSArray alloc] initWithObjects:#"Hello",nil];
[oldValues addObjectsFromArray:values];
[oldValues writeToFile:[self PathArray] atomically:YES];
[values release]; // Do not forget this line to avoid memory leak
In my item, the dictionary data includes null, for example :
{
"category_id" = 29;
"category_name" = "\U5f69\U6f2b";
coverurl = "<null>";
position = 29;
}
so writetofile, return value always FALSE.