Retrieve by specific file name from document directory in iOS - ios

Now i am retrieving file from document directory by specific name in iOS with following code.
NSMutableArray *arrayToSearch = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSError * error;
arrayToSearch = (NSMutableArray *)[[NSFileManager defaultManager] contentsOfDirectoryAtPath:[NSString stringWithFormat:#"%#/Manual.txt",documentsDirectory] error:&error];
I am sure i have the Manual.txt file in document directory.
However it doesn't show anything in tableView.
I also reload tableView.
Is there anything wrong?

The method is contentsOfDirectoryAtPath:. Read the name of the method. Read the description in the docs. The path you pass must reference a directory, not a file.
What you are trying to do doesn't make sense logically. If you know a specific file, then why search for it? Why create an array?
If you want to see if the file exists, use the fileExistsAtPath: method of NSFileManager.
If you just want the filename in the array then do:
NSString *filename = [documentsDirectory stringByAppendingPathComponent:#"Manual.txt"];
[arrayToSearch addObject:filename]; // since the array was pre-allocated
Please don't use stringWithFormat to create the filename. Use the proper NSString path methods like I did above.

Related

Will property list data persist after killing the application?

I have created a custom property list file. The file is stored in the application document.
While user login is successful the login information is stored in the plist, and it is working fine.
The plist content are cleared while log out, this also works fine.
When i am still login i killed the application. When the app opens the plist data i cleared.
code used to save to file:
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"xxxxPlist.plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
plistPath = [[NSBundle mainBundle] pathForResource:#"xxxxPlist" ofType:#"plist"];
}
dict=[[self cleanDictionary:[dict mutableCopy]] mutableCopy];
NSDictionary *plistDict=[[NSDictionary alloc] initWithObjectsAndKeys:dict,#"login_data", nil];
NSError *error = nil;
NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 options:NSPropertyListImmutable error:&error];
if(plistData)
{
[plistData writeToFile:plistPath atomically:YES];
}
else
{
//error here
NSLog(#"%# ",error);
}
code used to fetch data
NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"xxxx.plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
plistPath = [[NSBundle mainBundle] pathForResource:#"xxxxPlist" ofType:#"plist"];
}
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
return [dict objectForKey:#"login_data"];
I there any way out to persist the data?
There are several things that may be causing problems
When saving to file
1) My understanding is that you specifically want to save to /Documents folder specifically to ensure your file persists
2) So you correctly build following path
"/Documents/xxxxPlist.plist"
3) But then why do you check if a file already exists at that location?
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath])
{
plistPath = [[NSBundle mainBundle] pathForResource:#"xxxxPlist" ofType:#"plist"];
}
You just have to write to the path when you are ready.
If there is an old file at this location it will be overwritten.
And my understanding is this is the wanted behaviour, because you've already read that file and the data is in that dictionary "dict".
4) Also, by asking NSBundle to give you path for your file name
"xxxxPlist.plist"
there is a risk that it will just give you back some other path with file named the same (not in /Documents) if such file happens to exist. For example if you happened to write to say, /Cache folder earlier (with different code), your app will keep getting the /Cache path and keep reading/writong there (not in /Documents). And with the existing code you would have gotten nil here for path on the very first run, so not sure how he file got created in the first place.
5) Then I am not sure what exactly does this line
dict=[[self cleanDictionary:[dict mutableCopy]] mutableCopy];
Why first make a mutable copy, then presumably get immutable copy back and get a mutable one of it. Can't -cleanDictionary: just return the same mutable copy it was passed?
When reading from file
1) Not sure why you're searching for a different file first?
"/Documents/xxxx.plist" not "/Documents/xxxxPlist.plist"
Also what happens if "xxxx.plist" exists, then you'll never get to "xxxxPlist.plist" that you are writing in the other section.
2) Then, yes, you have to check if a file exists at certain path before you try to read it. But, in your case, if it does not exist, you don't ask NSBundle for another location, because you need your specific file in /Documents, and you don't know what you'll get from NSBundle, if your file is not where it should be.
So if there is no "xxxxPlist.plist" file, it's just your first run of the app and you will be creating your initial dict.

Retrieve all pdf files store in iPhone memory iOS (Objective-C)

I want to retrieve all the pdf documents from my iPhone, including all the pdf files that are stored in other apps like Adobe Acrobat.
What I have now is:
NSString *path = [NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
for (NSString *fileName in directoryContent) {
if ([fileName hasSuffix:#"pdf"]) {
//add files to an array
}
}
Which only points to one directory.
Firstly you are only getting the first path to the first directory, so you're only searching that one. Secondly, apple suggests to use the NSFileManager to search. Thirdly, be aware that developers of other apps can save their documents in different places, that you can't access or are not returned by these functions (Just so you are aware of this).
If you want to get array of all pdf files in Document directory, then use below code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSArray *arrPdfs = [[NSBundle bundleWithPath:[paths objectAtIndex:0]] pathsForResourcesOfType:#"pdf" inDirectory:nil];
arrPdfs will contain all pdfs in Document directory.

Loading files from disk to NSMutableArray removes NSMutableArray from memory

I'm loading a file to a NSMutableArray. I'm doing it like this:
if(!self.dataArray){
self.dataArray = [[NSMutableArray alloc] init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *arrayPath = [[paths objectAtIndex:0]
stringByAppendingPathComponent:#"array.out"];
self.dataArray = [NSMutableArray arrayWithContentsOfFile:arrayPath];
}
The array that is loaded into the file consists of multiple NSDictionaries.
However, this somehow deallocates the array in the memory because when I log dataArray after doing this, it logs nil. How come?
Update
I've figured out that [NSMutableArray arrayWithContentsOfFile:arrayPath] is logging nil because the code in which I'm uploading the content to the file, doesn't create the file:
// write data to disk
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *arrayPath = [[paths objectAtIndex:0]stringByAppendingPathComponent:#"array.out"];
[self.dataArray writeToFile:arrayPath atomically:YES];
NSLog(#"uploaded file: %#", arrayPath); // logs an arrayPath, but one that doesn't exists.
Check the following,
Check the dataArray is a weak property ? If so, change to strong.
Check the file exists at path, using
[[NSFileManager defaultManager] fileExistsAtPath:arrayPath];
Verify the file have expected content, by logging it.
Confirm the File content is organized as a property list (plist). Verify it in plist editor/Xcode.
If you dynamically creating it, check the path you are writing to.
Confirm the method of writing NSArray to plist. Use
[array writeToFile:path atomically:YES];
Note:
If you are dynamically creating the file and you are testing on Simulator; you can
find the file by logging file path and following it on Finder.
Property List Reference
Apple documentation
Per Apple documentation, the array returns nil if the file can’t be opened or if the contents of the file can’t be parsed into an array.
Did you use the [writeToFile:atomically:] method to write the array to a file?
Also, make sure that the filePath string matches exactly on both write and read ends. I've wasted a lot of time trying to hunt down a bug when it turned out I had misspelled the name of the file or used the wrong file extension.
Another possibility: have you confirmed that this code is being executed? Sometimes I've had to change (!self.someProperty) to (self.someProperty != nil) in my if condition to get code like this to run.
Peter Segerblom and wildBillMunson are right: the array returns nil if the file can't be opened or if its content can't be parsed into an array.
You said "array.out" is an array of NSDictionaries. Whenever I have that set of data, I use the plist type of file and read it this way:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *directory = [paths objectAtIndex:0];
NSString *fullPath = [directory stringByAppendingPathComponent:#"data.plist"];
NSString *errorDesc = nil;
NSPropertyListFormat format;
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:fullPath];
NSArray *data = (NSArray *)[NSPropertyListSerialization propertyListFromData:plistXML mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&errorDesc];
Be sure to check if fullPath is not returning nil.
Hope this helps!

How to save 2 NSMutableDictionary on disk

The development is in Xcode for iOS. I used 2 separate NSmutabledictionary.
I DON´T want to add them (when searching I found that often, but that is not what I try to do)
The app has to store them on the disk and when the app launches it can read the dictionary.
It is not a custom class so initWithCoder and the other one is not necessary (is this right?)
NSArray *data = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [data objectAtIndex:0];
path = [path stringByAppendingPathComponent:#"location"];
[NSKeyedArchiver archiveRootObject:"Dictionary" toFile:path];
This works but when I want to save another dictionary it won't work. My first thought would be to change the objectAtIndex to 1. But Xcode gives me an error when I do that. When I only give another name it simply won't save, but Xcode don't give an error.
What am I doing wrong?
// Find out where the documents folder is
NSString *documentsDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
// Create the file path for a file named 'location' inside the documents folder
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"location"];
// Write an array containing both of your arrays to a file at that path
[NSKeyedArchiver archiveRootObject:#[myFirstArray, mySecondArray] toFile:path];
Then, to read them back:
// Read back the array containing the two arrays
NSArray *arrays = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
// Get the individual arrays from the array
NSMutableArray *myFirstArray = arrays[0];
NSMutableArray *mySecondArray = arrays[1];

Content is not retrieved from file

I've got this wired problem, I cannot get the content from the file and initiate my NSMutableArray with it.
Here's my code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSLog(#"Does file exist?: %i", [[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithFormat: #"%#/length.txt", documentsDirectory]]);
NSMutableArray *tempArr;
tempArr = [[NSMutableArray alloc] initWithContentsOfFile:[NSString stringWithFormat: #"%#/length.txt", documentsDirectory]];
When trying this, initWithContentsOfFile returns (null). The row checking if the file exist prints '1' to the console.
This is the code I'm using to save the data:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
[length.text writeToFile:[NSString stringWithFormat: #"%#/length.txt", documentsDirectory] atomically:NO];
I'm using more or less exactly the same code in a different program without problems.
Really need some help here, perhaps I'm just blind for the moment...
When you try to create an array from the contents of a file, the file must be in plist format, and the outer-most plist element must be <array>. If it doesn't have that format, initialization will fail and your array will be nil.
You're creating the file by writing an NSString to a file, which means you should probably be reading it in to an NSString, not an NSArray.
The docs for NSArray's initWithContentsOfFile: method say:
Return Value An array initialized to contain the contents of the file
specified by aPath or nil if the file
can’t be opened or the contents of the
file can’t be parsed into an array.
The returned object might be different
than the original receiver.
You don't include the declaration of length in your code snippet, but I'm guessing that length.text returns an NSString object, not an NSArray. So you'd need to read that back from a file using initWithContentsOfFile: from NSString, not NSArray.

Resources