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);
Related
I have an api inside are the city's ID, I do not want to request data every time,I want to writeToFile as plist,but the first written is too slow and memory skyrocketing.
Is there any method I can use to make it into a plist as local file,so users do not have to write again
Plist file obtained in this way is no data on the xcode view, but in fact it has already been written, you can find data through code
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *plistPath = [paths objectAtIndex:0];
NSMutableArray *marr = [NSMutableArray array];
NSString *filename=[plistPath stringByAppendingPathComponent:#"city.plist"];
NSLog(#"filename == %#",filename);
[marr addObject:#"字符串"];
[marr writeToFile:filename atomically:YES];
If you are about to create Plist without programmatically then follow these steps :
Right Click on Files and Select 'New File...' option.
Choose Resources from OS X tab.
An option for Property List is available.
Select an give an appropriate name.
This gets added to your project.
You can create a property list in Objective-C if all of the objects in the aggregate derive from the NSDictionary, NSArray, NSString, NSDate, NSData, or NSNumber class.
Use following code:
//Get the documents directory path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"plist.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path]) {
path = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat:#"plist.plist"] ];
}
NSMutableDictionary *data;
if ([fileManager fileExistsAtPath: path]) {
data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
}
else {
// If the file doesn’t exist, create an empty dictionary
data = [[NSMutableDictionary alloc] init];
}
//To insert the data into the plist
[data setObject:#"iPhone 6 Plus" forKey:#"value"];
[data writeToFile:path atomically:YES];
//To retrieve the data from the plist
NSMutableDictionary *savedValue = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSString *value = [savedValue objectForKey:#"value"];
NSLog(#"%#",value);
For more details click here
Apple has also put a demo project for creating plist file here.
I wrote a class that caches API responses, so later when u request Countries endpoint, it will check defined endpoints to cache, if it find it in list and it exist in cache, it will return the cached one and will not complete performing the HTTP request, in docs i provided steps how to implement it.
MGCacheManager
Following function take serilizable object(dictionary, array) as input and convert it into plist and write it in document disrectory of application:
+ (BOOL) writeBundelPlist : (NSString *) plistName with : (id) newPlistData {
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:plistName];
if (![fileManager fileExistsAtPath:plistPath]) {
NSString *bundle = [[NSBundle mainBundle] pathForResource:[plistName stringByDeletingPathExtension] ofType:[plistName pathExtension]];
NSLog(#"plistPath = %#", plistPath);
[fileManager copyItemAtPath:bundle toPath:plistPath error:&error];
}
return [newPlistData writeToFile:plistPath atomically:YES];
}
this method is very useful, thanks for evervone,thanks for rmaddy
do{
let data = try NSPropertyListSerialization.dataWithPropertyList(response.result.value as! NSMutableDictionary, format: NSPropertyListFormat.XMLFormat_v1_0, options: 0)
data.writeToFile(countryListPath, atomically: true)
}catch
{
}
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"];
I am using writeToFile:atomically: to update the value of a key in my plist by 1 every time the app is launched. I put this code in viewDidLoad, which reads the string value of the key, gets the numeric value of that string, increases it by 1, converts it back to a string, and writes that as the new string for that key, but when I read it again it seems to have not updated. I can't figure out what I'm doing wrong. I don't need a special framework for writeToFile:atomically:, do I?
Here is the code:
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"DaysLaunched.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"DaysLaunched" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath:path error:&error];
}
NSMutableDictionary *plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSMutableDictionary *data1 = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
NSString *currentNumberOfDays = [NSString stringWithFormat:#"%#",[plistDict objectForKey:#"numberOfDays"]];
NSLog(#"currentNumberOfDays = %#", currentNumberOfDays); //0
int days = [currentNumberOfDays intValue];
days ++;
currentNumberOfDays = [NSString stringWithFormat:#"%d", days];
[data1 setObject:[NSString stringWithFormat:#"numberOfDays"] forKey:currentNumberOfDays];
NSLog(#"currentNumberOfDays = %#", currentNumberOfDays); //1
[data1 writeToFile: path atomically:YES];
currentNumberOfDays = [NSString stringWithFormat:#"%#",[plistDict objectForKey:#"numberOfDays"]];
NSLog(#"currentNumberOfDays = %#", currentNumberOfDays); //0 ??????? writeToFile isn't working?
And here is a screenshot of "DaysLaunched.plist" in my 'Supporting Files' folder, (I've also verified that the plist file name is spelled exactly the same way I spelled it in my code, via Copy-Paste)
The original plist file is also in my 'Copy Bundle Resources' in targets.
Try
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"DaysLaunched.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"DaysLaunched"
ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath:path error:&error];
}
NSMutableDictionary *plistDict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
NSInteger days = [plistDict[#"numberOfDays"] integerValue];
plistDict[#"numberOfDays"] = [#(++days) stringValue];
[plistDict writeToFile: path atomically:YES];
You have made a mistake while setting your data.
You should do:
[data1 setObject:currentNumberOfDays forKey:#"numberOfDays"];
instead of:
[data1 setObject:[NSString stringWithFormat:#"numberOfDays"] forKey:currentNumberOfDays];
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.
Using this code I am trying to get the data from Templates.plist file but I am getting null value in array.
//from plist
NSString *path = [[NSBundle mainBundle] pathForResource:#"Templates" ofType:#"plist"];
NSMutableArray *arry=[[NSMutableArray alloc]initWithContentsOfFile:path];
NSLog(#"arrayArray:::: %#", arry);
This is my plist file:
Also I want to know how can I add more strings to this plist file and delete a string from this plist.
First off you cannot write to anything in you mainBundle. For you to write to you plist you need to copy it to the documents directory. This is done like so:
- (void)createEditableCopyOfIfNeeded
{
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:#"Template.plist"];
success = [fileManager fileExistsAtPath:writablePath];
if (success)
return;
// The writable file does not exist, so copy from the bundle to the appropriate location.
NSString *defaultPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Template.plist"];
success = [fileManager copyItemAtPath:defaultPath toPath:writablePath error:&error];
if (!success)
NSAssert1(0, #"Failed to create writable file with message '%#'.", [error localizedDescription]);
}
So calling this function will check if the file exists in the documents directory. If it doesn't it copies the file to the documents directory. If the file exists it just returns. Next you just need to access the file to be able to read and write to it. To access you just need the path to the documents directory and to add your file name as a path component.
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [docDir stringByAppendingPathComponent:#"Template.plist"];
To get the data from the plist:
NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:filePath];
To write the file back to the documents directory.
[array writeToFile:filePath atomically: YES];
-(NSMutableArray *)start1
{
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:#"Templates.plist"];
if ([[NSFileManager defaultManager] fileExistsAtPath:plistPath]){
plistArr = [NSMutableArray arrayWithContentsOfFile: plistPath];
}
else {
plistArr = [[NSMutableArray alloc] init];
}
return plistArr;
}
- (void)createNewRecordWithName:(NSMutableDictionary *)dict
{
plistArr=[self start1];
[plistArr addObject: dict];
//[dict release];
[self writeProductsToFile:plistArr];
}
- (void)writeProductsToFile:(NSMutableArray *)array1 {
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:#"Template.plist"];
[array1 writeToFile:plistPath atomically:YES];
}
To get a plist into a mutable array, use this class method:
NSMutableArray *array = [NSMutableArray arrayWithContentsOfFile:path];
Then, add/delete strings from the array. To save the array back to a plist, use:
[array writeToFile:path atomically:YES];