I'm writing to and reading from a plist in my document directory. First I write the file out if there is no file found. That seemed to work correctly because at first there was no file there and now there is and double-clicking on the file shows the expected content of a key called TOSAcceptedValue with a value of NO.
But if the file is found, which happened after I ran the above once, I try to read in that same value, I'm getting a null value. Here's the code, it may not be pretty as I've been hacking at it for a while to get it to function.
NSError *error;
NSString *TOSAcceptedStatus ;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSLog( #"paths is %#", paths);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"AppUsage.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
//first see if file exists. if it doesn't then write it out with a value of NO for Terms of Use Accepted
if (![fileManager fileExistsAtPath: path])
{
NSMutableDictionary *appUsageNo = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
//here add element to data file and write data to file
NSString *value = #"NO";
[appUsageNo setObject:#"TOSAcceptedValue" forKey:value];
[appUsageNo writeToFile: path atomically:YES];
[appUsageNo release];
//and set TOSAcceptedStatus to no since we know its a no right now
TOSAcceptedStatus = #"NO";
}
else { //file was found at expected location so let's see if they accepted Terms of Use already
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSLog( #"path is %#", path);
TOSAcceptedStatus = [dictionary objectForKey:#"TOSAcceptedValue"];
//NSLog(#"TOSAcceptedStatus is %#", TOSAcceptedStatus);
NSLog(#"TOSAcceptedStatus is %#", [dictionary objectForKey:#"TOSAcceptedValue"]);
[dictionary release];
}
and here's my Console results
2011-09-09 21:47:23.177 myApp[1027:207] paths is (
"/Users/user1/Library/Application Support/iPhone Simulator/4.3/Applications/34562D85-DBE9-4A4F-A142-JEFC1F4808D1/Documents"
)
2011-09-09 21:47:44.915 myApp[1027:207] path is /Users/user1/Library/Application Support/iPhone Simulator/4.3/Applications/34562D85-DBE9-4A4F-A142-JEFC1F4808D1/Documents/AppUsage.plist
2011-09-09 21:47:50.448 myApp[1027:207] TOSAcceptedStatus is (null)
Any clues why I can't get TOSAcceptedStatus back?
Also, am I allowed to write to and read from a plist after app started?
I think your main problem is that you have the object and key backwards:
[appUsageNo setObject:value forKey:#"TOSAcceptedValue"];
Related
how can I edit or change a value string from:
in this plist I need change or Set "NO" in Enabled Value from Item 2, I see a lot examples, but not working, or are deprecated, or don't use ARC, any idea or example code? please help guys
EDIT#1: I try this (not work)
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
path = [path stringByAppendingPathComponent:#"List.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:path]) {
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:CONTENT_DEFAULT ofType:PLIST];
[fileManager copyItemAtPath:sourcePath toPath:path error:nil];
}
NSArray* newContent = [[NSArray alloc]initWithContentsOfFile:path];
NSDictionary *Dict = [[NSDictionary alloc]initWithDictionary:[newContent objectAtIndex:2]];
[Dict setValue:#"NO" forKey:#"Enabled"];
[Dict writeToFile:path atomically:YES];
NOTE: not work, it crashes send me:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSDictionaryI 0x15de7ff0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key Enabled.', or Im wrong in something?
EDIT #2 new Try
NSString *path = [[NSBundle mainBundle] pathForResource:#"List" ofType:#"plist"];
NSString *savingPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSArray* newContent = [[NSArray alloc]initWithContentsOfFile:path];
NSMutableDictionary *Dict = [[NSMutableDictionary alloc]initWithDictionary:[newContent objectAtIndex:2]];
[Dict setValue:#"NO" forKey:#"Enabled"];
savingPath = [savingPath stringByAppendingPathComponent:#"Modified.plist"];
[Dict writeToFile:savingPath atomically:YES];
NSLog(#"newContent:%#",newContent);
NSArray *newnew = [[NSArray alloc]initWithContentsOfFile:savingPath];
NSLog(#"newnew:%#",newnew);
NOTE: now print me a crash:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (3) beyond bounds (2)'
All you have to do is to use NSMutableDictionary instead of a regular dictionary to modify stuff. You have to always check that the object you are editing is there.
To get the right path for the plist you created in Xcode you need to use:
NSString *path = [[NSBundle mainBundle] pathForResource:#"List" ofType:#"plist"];
You might actually want to save that file into the app's document directory. So you would use the following path for saving the content:
NSString *savingPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
savingPath = [savingPath stringByAppendingPathComponent:#"Modified.plist"];
[Dict writeToFile:savingPath atomically:YES];
Well, in your case the solution would be the following (when you have Dictionary as a member of Array):
NSString *path = [[NSBundle mainBundle] pathForResource:#"List" ofType:#"plist"];
NSArray *newContent = [[NSArray alloc]initWithContentsOfFile:path];
//iterating through all members since all of them has the string "YES" which should be replaced, otherwise, you will need to create a separate dictionary for each member
for ((i = 0; i < [newContent count]; i++)){
//here you take the member (dictionary) of the array
NSDictionary *dictOfArray = [newContent objectAtIndex:i];
[dictOfArray objectForKey:#"Enabled"]=#"NO";
}
//if you update the same pList you can use the same path (otherwise use another path)
[newContent writeToFile:path atomically:YES];
So, it works now.
Hi I am trying to make bookmarks for my browser.
Title of Page, Url of Page, any Comments related to page.
I tried to save it in plist, but unsuccessful. Can anyone can help me to save these thing to plist and retrive in table view. So, when user tap on title it will open url in UIWebView.
Here is the code I have tried, so far:
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"bookmarks.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"bookmarks" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath: path error:&error]; //6
}
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSString *writeUrl = #"Page URL One";
NSString *writeTitle = #"Page Title One";
NSString *writeComment = #"Page comments";
[data setObject:[NSString stringWithString:writeUrl] forKey:#"url"];
[data setObject:[NSString stringWithString:writeTitle] forKey:#"title"];
[data setObject:[NSString stringWithString:writeComment] forKey:#"comment"];
[data writeToFile: path atomically:YES];
NSMutableDictionary *savedUrl = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSString *value;
value = [[savedUrl objectForKey:#"url"] stringValue];
NSLog(#"%#", value);
UPDATE: I successfully saved and retrieved data to and from plist. Issue is comming in this line
value = [[savedUrl objectForKey:#"url"] stringValue];
By removing stringValue solve the problem.
value = [savedUrl objectForKey:#"url"];
Now My second issue. I make three items named url, title, comment, types String in plist file.
How can i store different urls. Like
name website: inforains
url: inforains.com
title: Info Rains
comment: good website articles
name website: hitechnology
url: hitechnology.com
title: Hitechnology
comment: hmmm
ans soo on..
how can I store data like this.. so all name website will show on tableview and when user click on anyone, data related to that website will show. I hope i clear my question.
To store multiple records as three items named url, title, comment, types String in plist file
change types from string to dictionary and store data in each dictionary individually for key as 1,2,3 ...
OR
Use three mutable array for each url,title and comment and add object at index 0 at the time of saving it.
and access them when required as nsmutable array.
Change this line
value = [[savedStock objectForKey:#"url"] stringValue];
to
value = [savedUrl objectForKey:#"url"];
because you are saving NSString in dictionary... not NSNumber.
Second issue:
//create mutable array to save all objects
NSMutableArray *objectsArray = [data objectForKey:#"objectsArray"];
if(!objectsArray) {
objectsArray = [[NSMutableArray alloc] init];
}
//create and add dictionary into array
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:#"url1", #"title1", #"comment2",nil] forKeys:[NSArray arrayWithObjects:#"url", #"title", #"comment",nil]];
[objectsArray addObject:dictionary];
[data setObject:objectsArray forKey:#"objectsArray"];
[data writeToFile: path atomically:YES];
// to read data
NSMutableDictionary *savedUrl = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSMutableArray *objectsArraySAved = [savedUrl objectForKey:#"objectsArray"];
for (NSMutableDictionary *dic in objectsArraySAved) {
NSLog(#"URL %#", [dic valueForKey:#"url"]);
}
Are you sure [data writeToFile: path atomically:YES]; works? It returns a BOOL, you should check it.
Are you sure savedURL != nil?
For your new problem, you should put all your dictionaries in a mutable array.
NSMutableArray *bookmarkArray = [[NSMutableArray alloc]init];
[bookmarkArray addObject:data];
hello I am trying to create a text file that will then store some data
- (IBAction)saveUser:(id)sender{
NSString *name = [nameField stringValue];
NSString *weight = [weightField stringValue];
NSDate *date = [datePick dateValue];
}
I want to be able to create a file that stores the following information and uses the name field as the name of the file. I also want to be able to load the file and read that data from it
Any help is appreciated
Thanking You
This is quite simple. But you might want to look into NSMutableDictionary instead. Both NSString and Dictionary have methods writeToFile:#"filename.txt".
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:[nameField stringValue] forKey:#"name"];
[dict setValue:[weightField stringValue] forKey:#"weight"];
[dict setValue:date forKey:#"date"];
[dict writeToFile:name atomically:YES];
you read from the file the same way,
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithContentsOfFile:name];
As simple as it gets
I think you may get some informations from class NSFileManager, such as like this,
[fileManager createFileAtPath:filePath contents:contentData attributes:NULL];
the contentData is NSData, and it includes the content of what you want to save, the filename is in filePath that you need to set.
Thanks!
I use the following code to copy a Resources plist file into the documents directory:
BOOL success;
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"Test-Info.plist"];
success = [fileManager fileExistsAtPath:filePath];
if (!success) {
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingFormat:#"Test-Info.plist"];
success = [fileManager copyItemAtPath:path toPath:filePath error:&error];
NSLog(#"Test-Info.plist successfully copied to DocumentsDirectory.");
}
I get the success message, which is great. I'm assuming it's been copied correctly into the documents folder.
However when I then try to read and write to the saved plist file it returns null:
Key entry in Test-Info.plist:
Key: EnableEverything
Type: Boolean
Value: YES
Write code:
NSString *adKey = #"EnableEverything";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
NSString *path = [documentsDirectoryPath stringByAppendingPathComponent:#"Test-Info.plist"];
NSMutableDictionary *plist = [NSDictionary dictionaryWithContentsOfFile: path];
NSString *enableEverything = [[plist valueForKey:adKey] stringValue];
NSLog(#"****** EXISTING: %# ******", enableEverything); // returns (null)
// Disable in plist.
[plist setValue:0 forKey:adKey]; // will this work?
[plist writeToFile:path atomically:YES]; // this doesn't throw an error?
NSString *enableEverything1 = [[plist valueForKey:adKey] stringValue];
NSLog(#"****** NOW: %# ******", enableEverything1); // returns (null)
Output:
****** EXISTING: (null) ******
****** NOW: (null) ******
My question is why are they (null) when they exist within the plist file?
You are trying to mutate an immutable object.
You need a NSMutableDictionary.
IE
NSMutableDictionary *plist = [[NSDictionary dictionaryWithContentsOfFile: path] mutableCopy];
Also check, if the plist object isnt nil, as any messages can be send to nil without raiing an error. this wouldnt fail, also nothing actually happens.
[plist setValue:0 forKey:adKey]; // will this work?
[plist writeToFile:path atomically:YES]; // this doesn't throw an error?
as the source path is nil, you are most like not copying the file during compilation bundling. drag it here:
Try this for nsbundle path for resource
NSString *path= [[NSBundle mainBundle] pathForResource:#"SportsLogo-Info" ofType:#"plist"];
Try allocating
NSMutableDictionary *plist = [[NSMutableDictionary alloc] initWithDictionary:[NSDictionary dictionaryWithContentsOfFile:path]];
Also check if the file has been copied or not. Go to Library=>Application Support=>iPhone Simulator=>folder named your version of simulator iOS=>Applications=>Find the right folder of your project=>Documents see if the plist file is there
I have a dictionary containing a JSON response and a plist file. I want to update the values in my plist file with the JSON response values. How would I do this?
this is what i did, im working on it now, but im getting there:
JSON to dictionary:
NSString *jsonString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
//NSLog(#"%#",jsonString);
NSArray *result = [jsonString JSONValue];
for(NSDictionary *dictionary in result){
return dictionary; //if you are getting more then one row, do something here
}
Saving the dictionary:
id plist = plistDict;
NSString *errorDesc;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:#"Data.plist"];
NSLog(#"%#",plistPath);
NSData *xmlData;
NSString *error;
xmlData = [NSPropertyListSerialization dataFromPropertyList:plist
format:NSPropertyListXMLFormat_v1_0
errorDescription:&error];
if(xmlData) {
if ([xmlData writeToFile:plistPath atomically:YES]) {
NSLog(#"Data successfully saved.");
}else {
NSLog(#"Did not managed to save NSData.");
}
}
else {
NSLog(#"%#",errorDesc);
[error release];
}
}
if you want to update values, I would say you should open the plist, place it in a dictionary, update the value in the dictionary, and save the dictionary to the plist again.
Hope this helps.
If you are working under Mac OS X 10.7 or iOS 5, there is a Foundation class called NSJSONSerialization that will read/write JSON files. Converting JSON to plist will be as simple as: (Implying you have ARC or GC on)
NSString *infile = #"/tmp/input.json"
NSString *oufile = #"/tmp/output.plist"
[[NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:infile]
options:0
error:NULL] writeToFile:oufile
atomically:YES];
However a conversion from plist to JSON will be more troublesome since NSDate and NSData objects cannot appear in JSONs. You may need to check the contents of the file and store the NSData and NSDate in an alternate way (like NSData as Base-64 strings and NSDate as their UNIX times)