My app in development is related to survey questions. (fun ones, not boring ones!) I want to create a tier system for each question relative to the user, each time they answer a specific question I want to associate a value to that question for that user, identifying how many times they've answered it.
I believe the way I need to achieve this is NSMutableDictionary and NSUserDefaults. This is a simplified version of my code:
NSMutableDictionary *questionTierDictionary = [[NSMutableDictionary alloc]init];
[[NSUserDefaults standardUserDefaults] objectForKey:#"questionTiers"];
[questionTierDictionary setObject:[NSNumber numberWithInt:4] forKey:#(2)];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"%#", questionTierDictionary);
Does this code save this data indefinitely to the app, or does it disappear once the user has closed the app? If so, do you have any suggestions on how I can easily test to see if the data was stored?
sandbox path :
~~ Documents:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
~~~ Caches:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDir = [paths objectAtIndex:0];
~~~ tmp:
NSString *tmpDir = NSTemporaryDirectory();
~~~ home sandbox:
NSString *homeDir = NSHomeDirectory();
~~~ for pic :
NSString *imagePath = [[NSBundle mainBundle] pathForResource:#"apple" ofType:#"png"];
UIImage *appleImage = [[UIImage alloc] initWithContentsOfFile:imagePath];
Example:
NSFileManager* fm=[NSFileManager defaultManager];
if(![fm fileExistsAtPath:[self dataFilePath]]){
//
[fm createDirectoryAtPath:[self dataFilePath] withIntermediateDirectories:YES attributes:nil error:nil];
//
NSArray *files = [fm subpathsAtPath: [self dataFilePath] ];
//
NSData *data = [fm contentsAtPath:[self dataFilePath]];
//
NSData *data = [NSData dataWithContentOfPath:[self dataFilePath]];
}
I hope I could help you!
NSUserDefaults save data permanently in you application directory till you remove it manually... to save a object in NSUserDefaults code like this
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:#"yourObject",#"yourKey", nil];
[[NSUserDefaults standardUserDefaults]setObject:dict forKey:#"dict"];
//fetch Like this
NSDictionary *dict1 = [[NSUserDefaults standardUserDefaults] objectForKey:#"dict"];
Related
Hello I have the following code which works perfect, it finds the Plist and assigns the NSDictionary to my NSArray called landingSites. The only problem is I want the user to be able to add sites so need to store the Plist in the user documents instead of the NSBundle:
plistPath = [[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"];
NSMutableDictionary *newDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
dictionaryKeys = [newDictionary allKeys];
self.landingSites = [dictionaryKeys sortedArrayUsingSelector:#selector(compare:)];
self.dictionaryFromPlist = newDictionary;
[Picker selectRow:0 inComponent:0 animated:NO];
for(NSString *parent in dictionaryKeys)
{
NSDictionary *parentData = [dictionaryFromPlist objectForKey:parent];
NSArray *child = [parentData objectForKey:#"Name"];
NSLog(#"%#", child);
}
So far I have produced the code below, but whenever I run the program, the if-statement ALWAYS executes as if the plist in never copied to the user documents. Also I do not know how to attach the NSDictionary contents to my landingSites array as I did above. Please help
(void) viewDidLoad {
[super viewDidLoad];
NSError *error;
NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Data.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:path]) {
NSLog(#"copying database to users documents");
NSString *pathToSettingsBundle = [[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"];
[fileManager copyItemAtPath:pathToSettingsBundle toPath:path error:&error];
}
else{
NSLog(#"users database already configured");
}
NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask,YES);
NSDocumentationDirectory is wrong. You are looking for NSDocumentDirectory or NSLibraryDirectory.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
I have a custom plist that I am using to populate UItableViewCells with, I am able to read them perfectly, however when I try to write to my custom plist file it never changes.
NSString *errorDesc = nil;
NSString * plistPath = [[NSBundle mainBundle] pathForResource:#"AdvanceSearchPrefrences" ofType:#"plist"];
NSMutableDictionary *advPrefs = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
[advPrefs setObject:cell.textLabel.text forKey:#"Manuf"];
[advPrefs setObject:selRow forKey:#"ManufNum"];
NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:advPrefs format:NSPropertyListXMLFormat_v1_0 errorDescription:&errorDesc];
[plistData writeToFile:plistPath atomically:YES];
NSString * plistPath2 = [[NSBundle mainBundle] pathForResource:#"AdvanceSearchPrefrences" ofType:#"plist"];
NSMutableDictionary *advPrefs2 = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath2];
The advPrefs shows the new values and advPrefs2 shows the old values.
You can't directly save over your plist, but what you can do is create a copy and save that to NSUserDefaults.
On the initial load you do something like this in your AppDelegate. This will copy your plist into something you can edit and save:
NSString * plistPath = [[NSBundle mainBundle] pathForResource:#"AdvanceSearchPrefrences" ofType:#"plist"];
NSMutableDictionary *advPrefs = [NSDictionary dictionaryWithContentsOfFile:plistPath];
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:advPrefs] forKey:#"plist"];
[[NSUserDefaults standardUserDefaults] synchronize];
In your class that you want to fetch the copied plist, you can call something like this:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:#"plist"];
NSMutableDictionary *advPrefs = [[NSKeyedUnarchiver unarchiveObjectWithData:data]mutableCopy];
Then make your changes
[advPrefs setObject:cell.textLabel.text forKey:#"Manuf"];
[advPrefs setObject:selRow forKey:#"ManufNum"];
And then save them to NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:advPrefs] forKey:#"plist"];
[[NSUserDefaults standardUserDefaults] synchronize];
I had this same problem with my app and this is how I fixed it. Hope this works for you too
Read data:
NSData *data;
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"AdvanceSearchPrefrences.plist"];
if (filePath) {
data = [[NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:&error]
dataUsingEncoding:NSUTF8StringEncoding];
// use data here....
}
Write data:
NSString *documentDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [documentDirectoryPath stringByAppendingPathComponent:#"AdvanceSearchPrefrences.plist"];
if ([dataToBeWritten writeToFile:path
atomically:YES
encoding:NSUTF8StringEncoding
error:&error]) {
// data is written
}
Normally I save data to a plist (just data that I don't really care if a JailBroken phone hacked, like users preferences and stuff) except when the user first launches the app I create the plist like so:
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathFirstTime = [documentsDirectory stringByAppendingPathComponent:#"FirstTime.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: pathFirstTime])
{
NSString *bundleFirstTime = [[NSBundle mainBundle] pathForResource:#"FirstTime" ofType:#"plist"];
[fileManager copyItemAtPath:bundleFirstTime toPath:pathFirstTime error:&error];
}
So I create a blank plist file in xcode and put it in the bundle and the first time the user launches the app it copies it to the documentsDirectory...
Is there anyway I can create the blank plist file in objective-c the first time that way I don't actually have to create one in Xcode and have it in the bundle but it will just get created automatically the first time the user launches the app...
Basically just avoiding this code: [fileManager copyItemAtPath:bundleFirstTime toPath:pathFirstTime error:&error];
[#{} writeToFile: pathFirstTime atomically: NO];
Create an NSArray or NSDictionary instance and use writeToFile:atomically:.
remove your whole code, this will do the trick
if(![[NSUserDefaults standardUserDefaults] objectForKey:#"FirstRun"]){
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pathFirstTime = [documentsDirectory stringByAppendingPathComponent:#"MyPlistFile.plist"];
[#{} writeToFile: pathFirstTime atomically: YES];
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:#"FirstRun"];
}
Want to add a new record ?
NSString *pathFirstTime = [documentsDirectory stringByAppendingPathComponent:#"MyPlistFile.plist"];
NSMutableDictionary *mdic = [[NSMutableDictionary alloc] initWithDictionary:[NSDictionary dictionaryWithContentsOfFile:pathFirstTime]];
[mdic setObject:[NSNumber numberWithInt:3] forKey:#"user-selected-color-scheme"];
[mdic writeToFile: pathFirstTime atomically: YES];
Read the plist file later ?
NSString *pathFirstTime = [documentsDirectory stringByAppendingPathComponent:#"MyPlistFile.plist"];
NSMutableDictionary *mdic = [[NSMutableDictionary alloc] initWithDictionary:[NSDictionary dictionaryWithContentsOfFile:pathFirstTime]];
NSLog(#"%#", mdic);
I want to save the token from from the server into a plist. I am not sure If I have to create a plist firs or it can automatically get created with the following code in my Document directroy. However, I am not able to create a plist and write my dictionary into it.
Here is my code
-(void)writeToPlist:(NSString*)value forkey:(NSString *)key
{
NSLog(#"Write plist here");
//NSError *error;
NSArray *paths=NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory=[paths objectAtIndex:0];
NSString* path=[documentDirectory stringByAppendingFormat:#"Util.plist"];
NSLog(#"The path is %#",path);
NSFileManager *fileManager=[NSFileManager defaultManager];
NSMutableDictionary *data;
if(![fileManager fileExistsAtPath:path])
{
path=[[NSBundle mainBundle]pathForResource:#"Util" ofType:#"plist"];
}
[data setObject:value forKey:key];
[data writeToFile:path atomically:YES];//will it create the plist?
}
why don't you save it using NSUserDefaults?
here's an example code :
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
if([standardUserDefaults objectForKey:#"your-key-goes-here"] == nil) //this means you don't have that key
{[standardUserDefaults setValue:#"your-value-goes-here" forKey:#"your-key-goes-here"];}
[standardUserDefaults synchronize];
don't forget to synchronize in the final.
and when you need the data you need to call standartUserDefaults's :valueForKey method.
hope this helps..
I found a way to easily create a plist file programatically, this works for me:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingString:#"/myFile.plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:path]){
NSDictionary *emptyDic = [NSDictionary dictionary];
[emptyDic writeToFile:path atomically:YES];
}
Change what is inside the if statement and it will work.
I want to write some values to an external file and use NSDictionary for this purpose:
NSString *s = #"123456";
NSString *key = #"key";
NSString *file = pathInAppDirectory(#"values");
NSDictionary *dic = [NSDictionary dictionaryWithObject:s forKey:key];
[dic writeToFile:file atomically:YES];
Ok, pathInAppDirectory looks like this:
NSString *pathInAppDirectory(NSString *fileName)
{
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES);
NSString *appDir = [documentDirectories objectAtIndex:0];
return [appDir stringByAppendingPathComponent:fileName];
}
What happens is exactly nothing: If I want to have look in the file somewhat later and want to display the values, null is returned. And a look into the folder of the iPhone simulator shows an empty folder, too. What happens there or, to be more specific: what does not happen?
You need to use NSDocumentDirectory instead of NSApplicationDirectory. It is not possible to write in the Application bundle.
Cleaned up example:
- (NSString *)pathInAppDirectory:(NSString *)fileName {
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *appDir = [documentDirectories objectAtIndex:0];
return [appDir stringByAppendingPathComponent:fileName];
}
NSString *s = #"123456";
NSString *key = #"key";
NSDictionary *dic = [NSDictionary dictionaryWithObject:s forKey:key];
NSString *filePath = [self pathInAppDirectory:#"values"];
[dic writeToFile:filePath atomically:YES];