overwriting instead of writing to a plist-cocoa - cocoa

I have created a method to write data to a plist.
- (void)writeToPListUserType:(NSString *)type
andUserID:(NSString *)usid
andFirstName:(NSString *)fname
andLastName:(NSString *)lname
andPassword:(NSString *)pwd{
NSMutableDictionary *userDetails = [[NSMutableDictionary alloc] init];
[userDetails setObject:fname forKey:#"firstName"];
[userDetails setObject:lname forKey:#"lastName"];
[userDetails setObject:pwd forKey:#"password"];
NSMutableDictionary *userIDKey = [[NSMutableDictionary alloc] init];
[userIDKey setObject:userDetails forKey:usid];
[userCredentials setObject:userIDKey forKey:type];
[userIDKey release];
[userDetails release];
NSString *error;
NSString *rootPath = [NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *plistPath = [rootPath stringByAppendingPathComponent:
#"userCredentials.plist"];
NSData *plistData = [NSPropertyListSerialization
dataFromPropertyList:userCredentials
format:NSPropertyListXMLFormat_v1_0
errorDescription:&error];
[plistData writeToFile:plistPath atomically:YES];
}
I am able to write new data to the plist. However, when the new data is written, the old data is no longer there. In other words, the method is overwriting my plist.
Please tell me what is wrong with the method... :(
Thanks in advance...

With this line:
code>[userCredentials setObject:userIDKey forKey:type];
you are overwriting the existing "userCredentials" "type" key (I don't see it is newly allocated in the method) with new data.
So the userCredentials, which I suppose is a mutable dictionary created elsewhere, is overwritten with the new data.

1) read the plist from disk
2) create a mutable in memory copy
3) modify the (in memory) plist
4) overwrite the file you read, using the in memory plist

Related

Read plist into nsmutabledictionary, update the dictionary and then save it again

I am really new to saving files in objective C but what I'm trying to accomplish is reading a plist file located in the documents directory on launch or creating it if it doesn't exist.
It should be read in to a NSMutableDictionary. Later on in the app I should be able to save items to the NSMutableDict with categories as keys + text.
The before launch in the viewWillUnload the NSMutableDictionary should be saved into the plist file again.
I have created the plist but I need a way to write to the NSMutableDictionary the right way (category and my result.text string.
And I also need to save the NSMutableDictionary to the plist file and read the plist into the dictionary on launch.
Some help with this would be awsome :D
Thanks guys.
In the savefile void I am doing this:
storeDict = [[ NSMutableDictionary alloc]
init];
[storeDict setObject:resultText.text forKey:#"kvitto"];
[storeDict setObject:kategori forKey:#"kategori"];
[storeDict writeToFile:[self saveFilePath] atomically:YES];
saveFilePath looks like this:
- (NSString *) saveFilePath {
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[path objectAtIndex:0] stringByAppendingString:#"savefile.plist"];
}
The values are strings collected from a code that the user have scanned so don't worry bout them.
Well so how do I save this correctly keeping the data that already exists in the savefile.plist.
Thanks again
If you want dictionaries and arrays contained in the dictionary to be mutable as well then do the following:
NSData *data = [NSData dataWithContentsOfFile:path];
NSError *error;
storeDict =
[NSPropertyListSerialization
propertyListWithData:data
options:NSPropertyListMutableContainersAndLeaves
format:nil
error: &error];
Why can't you use writeToFile api? Before writing question here you must google or check apple documentation for NSMutableDictionary.
[dict writeToFile:path atomically:YES];
To load saved dictionary
dict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
Happy coding!

Saving multiple objects to plist and somehow sorting them in to categories

So I am currently making a scanApp where it is necessarry to sort different objects in to different categories. So when the user scans a code and gets the result text the result should be saved into the plist file with that category.
This is my approach currently.
values = [[NSMutableArray alloc]initWithObjects:resultText.text, nil];
[values writeToFile:[self saveFilePath] atomically:YES];
- (NSString *) saveFilePath {
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[path objectAtIndex:0] stringByAppendingString:#"savefile.plist"];
}
It is the way that I've learnt, but how can I save things with (keys maybe) so that I can sort them.
Also how can I read the items with just that specific category.
Thanks everyone :)

Reading a plist

I'm trying to read ~/Library/Preferences/com.apple.mail.plist (on Snow Leopard) to get the email address and other information to enter into the about dialog. I'm using the following code, which is obviously wrong:
NSBundle* bundle;
bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"~/Library/Preferences/com.apple.mail.plist" ofType:#"plist"];
NSDictionary *plistData = [NSDictionary dictionaryWithContentsOfFile:plistPath];
NSString *item = [plistData valueForKeyPath:#"MailAccounts.Item 2.AccountName"];
NSLog(#"Result = %#", item);
Moreover, the value I need to read is MailAcounts -> Item 2 -> AccountName and I am not sure I am doing this correctly (due to the space in the Item 2 key).
I tried reading Apple's developer guide to plist files but no help there.
How can I read a plist and extract the values as an NSString?
Thanks.
The first level is an array, so you need to use "MailAccounts.AccountName" and treat it as NSArray*:
NSString *plistPath = [#"~/Library/Preferences/com.apple.mail.plist" stringByExpandingTildeInPath];
NSDictionary *plistData = [NSDictionary dictionaryWithContentsOfFile:plistPath];
NSArray *item = [plistData valueForKeyPath:#"MailAccounts.AccountName"];
NSLog(#"Account: %#", [item objectAtIndex:2]);
Alternatively you can go by keys and pull the array from "MailAccounts" first using valueForKey: (which will yield NSArray*) and then objectAtIndex: to get the dictionary of that particular account (useful if you need more than the name).
Two things:
You don't want or need to use NSBundle to get the path to the file. The file lies outside of the app bundle. So you should just have
NSString *plistPath = #"~/Library/Preferences/com.apple.mail.plist";
You have to expand the tilde in the path to the user directory. NSString has a method for this. Use something like
NSString *plistPath = [#"~/Library/Preferences/com.apple.mail.plist" stringByExpandingTildeInPath];

Sort a NSMutuableArray

I have a NSMutableArray that is loaded with a inforamtion from a dictionary...
[self.data removeAllObjects];
NSMutableDictionary *rows = [[NSMutableDictionary alloc] initWithDictionary:[acacheDB.myDataset getRowsForTable:#"sites"]];
self.data = [[NSMutableArray alloc] initWithArray:[rows allValues]];
There are two key value pairs in the rows dictionary.
I need to sort the self.data NSMutableArray in alphabetical order.
How is this accomplished??
thanks
tony
If the values are plain strings you can use the following to create a sorted array:
NSArray *sorted = [values sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
This should do:
[self.data removeAllObjects];
NSArray *values = [[acacheDB.myDataset getRowsForTable:#"sites"] allValues];
NSSortDescriptor *alphaDescriptor = [[NSSortDescriptor alloc] initWithKey:#"DCFProgramName" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)];
NSArray *sortedValues = [values sortedArrayUsingDescriptors:[NSMutableArray arrayWithObjects:alphaDescriptor, nil]];
[alphaDesc release];
[self.data addObjectsFromArray:sortedValues];
There's no need to clear an NSMutableArray if you're replacing it shortly afterwards.
There's no need to create an additional NSMutableDictionary, if you're not modifying anything in it.
There's no need to create an additional NSMutableArray, if you could just as well just add the values to the existing one.
Also: There are some serious memory leaks in your code. (2x alloc + 0x release = 2x leak)
Edit: updated code snippet to reflect OP's update on data structure.

Problems with UIImagePNGRepresentation

I'm trying to use this line of code
[UIImagePNGRepresentation(image, 1.0) writeToFile:pngPath atomically:YES];
But obviously pngPath is undeclared. So I have to use stringByAppendingPathComponent.
I googled examples of this, and I found this
myPlistPath = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat: #"%#.plist", plistName] ];
[myPlistPath retain]
;
The problem is that I don't have a plist file, because I don't need one. How can I solve all these issues and writeToFile the UIImage image?
I don't fully understand your question, but to get the full path where your file should be saved, you could try this:
NSString *file = #"myfile.png";
NSString *directory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) objectAtIndex:0];
NSString *path = [directory stringByAppendingPathComponent: file];
and then:
[UIImagePNGRepresentation(image) writeToFile:path atomically:YES];

Resources