I'm trying to save some user settings using NSDictionary writetofile but it is not working.
I have already checked out similar questions but I could not find out what the problem is.
here's my code:
NSDictionary *settings;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *settingsPath = [NSString stringWithFormat:#"%#/UserSettings.plist", [paths objectAtIndex:0]];
BOOL settingsExist = [[NSFileManager defaultManager] fileExistsAtPath:settingsPath];
if(settingsExist){
NSLog(#"file found!");
settings = [NSDictionary dictionaryWithContentsOfFile:settingsPath];
}else{
NSLog(#"file not found!");
settings = [[NSDictionary alloc] initWithObjectsAndKeys:#"iPhone",#"device", nil];
[[NSFileManager defaultManager] createFileAtPath:settingsPath contents:nil attributes:nil];
if([settings writeToFile:settingsPath atomically:YES]){
NSLog(#"success!");
}else{
NSLog(#"fail!");
}
}
It keeps returning 'fail!'.
Could you help me with this please?
You need to specify NSDocumentDirectory rather than NSDocumentationDirectory.
Related
I am creating a directory inside my application.Is there a code to view the contents of the directory in xcode. For example in android you can create a custom directory and view its contents using a file manager application. Can the similar procedure be done in apple?
Here is the code which i use to create a directory?
bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
fileManager = [NSFileManager defaultManager];
myImageDirectory = [fileManager URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask];
if ([myImageDirectory count] == 1){
NSLog(#"myImageDirectoryIs already present directory is already present");
}else{
directoryPath = [[myImageDirectory objectAtIndex:0] URLByAppendingPathComponent:bundleIdentifier];
NSLog(#"myImageDirectory directory name = %#",[directoryPath absoluteString]);
NSError *theError = nil;
if (![fileManager createDirectoryAtURL:directoryPath withIntermediateDirectories:NO attributes:nil error:&theError]){
NSLog(#"didnt write image data");
}else{
imagePath = [[directoryPath absoluteString] stringByAppendingPathComponent:[NSString stringWithFormat:#"/%#_%#_%#_image.jpg",dIdNo,iIdNo,[self currentDateandTime]]];
[imageData writeToFile:imagePath atomically:YES];
}
}
If your app is running in the simulator you'll need to use Finder. Go to the following directory:
/Users/<username>/Library/Application Support/iPhone Simulator/<iOS version>/Applications/<uuid>/Library/Application Support
If your app is running on the device you can use Xcode:
Connect the device
Choose menu option Window -> Organizer
Go to the Devices Tab
Click Applications under the device menu on the left
Pick your Application
The directory contents will be listed and you can optionally download everything.
try this...
to create a directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:#"/MyFolder"];
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error]; //Create folder
to retrieve contents from directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *customDirectory = [documentsDirectory stringByAppendingPathComponent:#"/MyFolder"];
NSError * error;
NSArray *directoryContents = [[NSFileManager defaultManager]
contentsOfDirectoryAtPath:customDirectory error:&error];
for(NSString *strFile in directoryContents)
{
NSString *strVideoPath = [NSString stringWithFormat:#"%#/%#",customDirectory,strFile];
if([[strVideoPath pathExtension] isEqualToString:#"mp4"] || [[strVideoPath pathExtension] isEqualToString:#"mov"])
{
[urlArray addObject:strVideoPath];
}
}
you can get the contents of the directory(MYNewFolder) from below code:
NSString *stringPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:#"MYNewFolder"];
NSArray *filePathsArray = [[NSFileManager defaultManager]
subpathsOfDirectoryAtPath:stringPath
error:nil];
for ( NSString *apath in filePathsArray )
{
NSLog(#"inside the file path array=%d",apath);
}
Method
-(NSArray *) getObjectsInDirectory:(NSString *)directory {
NSFileManager * fm = [NSFileManager defaultManager];
NSError * error = nil;
NSArray * result = [fm contentsOfDirectoryAtPath:directory error:&error];
return result;
}
How-To
NSString * documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSArray * files = [self getobjectsInDirectory:documentsPath];
This code is used to get an array of the files within the documents directory.
Viewing the Files
NSLog(#"%#", files);
Check this class out, it allows you to simplify so many things in iOS: Atomic Class
I am trying to add and array to a Root array in my plist:
And is not working. Here's my code:
-(IBAction)addName:(id)sender{
NSArray *arrayValues = [NSArray arrayWithObjects: nameLabel.text, nameDate.text, nameValue.text, nil];
NSString *plistpath = [[NSBundle mainBundle] pathForResource:#"Names" ofType:#"plist"];
NSMutableArray *namesNew = [[NSMutableArray alloc] initWithContentsOfFile:plistpath];
[namesNew addObject:arrayValues];
[namesNew writeToFile:plistpath atomically:YES];
}
What am I doing wrong? Thanks!
You need to move the file to NSDocumentDirectory. Then edit the plist file.
For example:
Moving to NSDocumentDirectory:
-(NSDictionary *)copyBundleToDocuments
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [documentPaths objectAtIndex:0];
NSString *documentPlistPath = [documentsDirectory stringByAppendingPathComponent:#"Names.plist"];
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *bundlePlistPath = [bundlePath stringByAppendingPathComponent:#"Names.plist"];
//if file exists in the documents directory, get it
if([fileManager fileExistsAtPath:documentPlistPath])
{
NSMutableDictionary *documentDict = [NSMutableDictionary dictionaryWithContentsOfFile:documentPlistPath];
return documentDict;
}
//if file does not exist, create it from existing plist
else
{
NSError *error;
BOOL success = [fileManager copyItemAtPath:bundlePlistPath toPath:documentPlistPath error:&error];
if (success) {
NSMutableDictionary *documentDict = [NSMutableDictionary dictionaryWithContentsOfFile:documentPlistPath];
return documentDict;
}
return nil;
}
}
Then get the plist:
-(void)plistArray:(NSArray*)array
{
//get the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//getting the plist file name:
NSString *plistName = [NSString stringWithFormat:#"%#/Names.plist",
documentsDirectory];
NSMutableArray *namesNew = [[NSMutableArray alloc] initWithContentsOfFile:plistName];
[namesNew addObject:arrayValues];
[namesNew writeToFile:plistName atomically:YES];
return nil;
}
The plist should be a dictionary as the base object instead of an array.
NSMutableDictionary *namesNew = [NSMutableDictionary dictionaryWithContentsOfFile:plistpath];
[namesNew setObject: arrayValues forKey: #"Root"];
[namesNew writeToFile:plistpath atomically:YES];
You cant write your plist to the bundle you need to use NSDocumentDirectory or NSCachesDirectory
Just copy your plist to bundle the overwrite it.
Note: learn the difference between NSCachesDirectory and NSDocumentDirectory
https://developer.apple.com/icloud/documentation/data-storage/
Copy your plist from bundle to documents(in below code caches), you need to this only one time if your plist in your bundle, I prefer using this code in appdelegate.m when - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Names.plist"];
NSString *plistInDocuments=#"Names.plist";
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:plistInDocuments];
NSError *error = nil;
if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath]){
[[NSFileManager defaultManager] copyItemAtPath:sourcePath
toPath:dataPath
error:&error];
}
NSLog(#"Error description-%# \n", [error localizedDescription]);
NSLog(#"Error reason-%#", [error localizedFailureReason]);
Get your file and overwrite it
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistInDocuments=#"Names.plist";
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:plistInDocuments];
//add object here
NSMutableArray *namesNew = [[NSMutableArray alloc] initWithContentsOfFile:dataPath];
[namesNew addObject:arrayValues];
NSError *error = nil;
if ([myFile writeToFile:dataPath options:NSDataWritingAtomic error:&error]) {
// file saved
} else {
// error writing file
NSLog(#"Unable to write plist to %#. Error: %#", dataPath, error);
}
I've spent the past few hours trying to figure this out, but I've ran out of ideas.
All I'm trying to do is archive an object, but the method archiveRootObject keeps on returning NO
Here's my code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
cacheDirectory = [cacheDirectory stringByAppendingPathComponent:#"MyAppCache"];
NSString *fullPath = [cacheDirectory stringByAppendingPathComponent:#"archive.data"];
if(![[NSFileManager defaultManager] fileExistsAtPath:fullPath]){
[[NSFileManager defaultManager] createDirectoryAtPath:fullPath withIntermediateDirectories:YES attributes:nil error:nil];
}
NSArray *array = [NSArray arrayWithObjects:#"hello", #"world", nil];
NSLog(#"Full Path: %#", fullPath);
BOOL res = [NSKeyedArchiver archiveRootObject:array toFile:fullPath];
if(res){
NSLog(#"YES");
}else{
NSLog(#"NO");
}
Every time time I run this, it prints NO.
Any help would be appreciated!
You create a directory with the path fullPath and then you try to write the file at the same path. Overwriting a directory with a file like this is not possible. Use your cacheDirectory string to create your directory.
NSString *cacheDirectory is not a mutable string and after you init it, you attempt to modify it so you are writing to the top-level directory.
For a quick fix, try:
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *documentPath = ([documentPaths count] > 0) ? [documentPaths objectAtIndex:0] : nil;
NSString *documentsResourcesPath = [documentPath stringByAppendingPathComponent:#"MyAppCache"];
NSString *fullPath = [documentsResourcesPath stringByAppendingPathComponent:#"archive.data"];
Is it actually possible to call NSKeyedArchiver archiveRootObject and work with data protection API setting the file attribute to NSFileProtectionComplete or NSFileProtectionCompleteUnlessOpen ?
First attempt to write the object to the specific location, in this case docFile (this is set to the documents directory). Then apply the file attributes to the docFile.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex: 0];
NSString* docFile = [docDir stringByAppendingPathComponent: #"Somefile.plist"];
NSError* error;
if([NSKeyedArchiver archiveRootObject:tempData toFile:docFile]) {
NSDictionary *fileAttributes = [NSDictionary
dictionaryWithObject:NSFileProtectionComplete
forKey:NSFileProtectionKey];
if([[NSFileManager defaultManager] setAttributes:fileAttributes
ofItemAtPath:docFile error: &error]) {
NSLog(#"Success");
}
else {
NSLog#(%#", error);
}
}
In my app I download a pdf file with an ASiHttpRequest and I have these instructions:
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[currentDownload setDownloadDestinationPath:[documentsDirectory stringByAppendingPathComponent:#"file.pdf"]];
it work fine at first time, and I can open this file.pdf, but when I download a second time this pdf, it seems that it not replace the file but do a merge.
before I do this, but it doesn't work where is the problem, or what's the best way to delete this file.pdf from its path?
- (void) removeFile{
NSString *extension = #"pdf";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPDF = [paths objectAtIndex:0];
NSArray *contents = [fileManager contentsOfDirectoryAtPath:documentsDirectoryPDF error:NULL];
NSEnumerator *e = [contents objectEnumerator];
NSString *filename;
while ((filename = [e nextObject])) {
if ([[filename pathExtension] isEqualToString:extension]) {
[fileManager removeItemAtPath:[documentsDirectoryPDF stringByAppendingPathComponent:filename] error:NULL];
}
}
}
EDIT
now I use this method
- (void) removeFile{
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0]stringByAppendingString:#"/file.pdf"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSLog(#"Documents directory before: %#", [fileManager contentsOfDirectoryAtPath:[paths objectAtIndex:0] error:&error]);
if([fileManager fileExistsAtPath:path] == YES)
{
NSLog(#"file exist and I delete it");
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:path error:&error];
NSLog(#"error:%#", error);
}
NSLog(#"Documents directory after: %#", [fileManager contentsOfDirectoryAtPath:[paths objectAtIndex:0] error:&error]);
}
this method recognize that in directory there is "file.pdf" in NSLog
NSLog(#"Documents directory before: %#", [fileManager contentsOfDirectoryAtPath:[paths objectAtIndex:0] error:&error]);
but it crash after
"NSLog(#"file exist and I delete it");"
and I have only a "lldb" in consolle.
I use this method to delete pdf files from a local cache, with a few modifications you can adapt it to your necessities
- (void)removePDFFiles
{
NSFileManager *fileMngr = [NSFileManager defaultManager];
NSArray *cacheFiles = [fileMngr contentsOfDirectoryAtPath:[self cacheDirectory]
error:nil];
for (NSString *filename in cacheFiles) {
if ([[[filename pathExtension] lowercaseString] isEqualToString:#"pdf"]) {
[fileMngr removeItemAtPath:[NSString stringWithFormat:#"%#/%#", [self cacheDirectory], filename] error:nil];
}
}
}
Most probably you don't remove the file before downloading a new one and ASIHttpRequest sees that there's already a file with the same name and appends data to it instead of replacing the file. I'm not sure about the PDF format, but that shouldn't normally result in a merged readable file. In any case, first you need to use the error mechanism that the filemanager class offers you. Is bad to pass NULL. Very bad. So, create a NSError object and pass it to the contentsOfDirectoryAtPath and removeItemAtPath methods, then check the error, be sure the operations are done successfully. After that, you may want to check the extension upper case as well, as Unix based systems are case sensitive (although the simulator is not, the device is) and a example.PDF file will not get deleted based on your code.
Try the following:
-(BOOL) removePDF
{
BOOL removeStatus = NO;
NSArray *dirPaths;
NSString *docsDir;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString* fileName = #"file.pdf"; //your file here..
NSString* filePath = [NSString stringWithFormat:#"%#/%#", docsDir, fileName];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath] == YES)
{
removeStatus = [[NSFileManager defaultManager] removeItemAtPath:filePath];
}
return removeStatus;
}