I was using
NSURL *applicationDocumentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
to get the application directory in the IOS simulator. In my previous projects, I get path like:
Users/username/Library/Application%20Support/iPhone%20Simulator/7.1-64/Applications/30CF9489-8AE3-49D4-9E01-DC14EBA2E08D/Documents/
However, in one of my projects, it returns
Users/username/Library/Application%20Support/iPhone%20Simulator/7.1-64/Applications/30CF9489-8AE3-49D4-9E01-DC14EBA2E08D/Library/Documentation
Why they return two different paths while I am using the same method?
Because in the 2nd case you are using NSDocumentationDirectory instead of NSDocumentDirectory.
Related
I am a React native developer and I was trying to integrate a native ios code.
One of the instance takes NSURL * which should be a local path I guess
https://github.com/uber/startup-reason-reporter/blob/master/StartupReasonReporter/StartupReasonReporterPriorRunInfo/UBApplicationStartupReasonReporterPriorRunInfo.h#L21
+ (nonnull instancetype)priorRunAtDirectoryURL:(nullable NSURL *)directoryURL;
I am not sure what does localPath Url looks like in IOS, like what should I pass? for example?
Ps: intentionally including swift tag as well because I think swift developers could also answer it.
Based on description of that function:
Returns the prior run information stored to disk at the given directory URL.
#param directoryURL The directory to use to to store the startup reason data.
#return the previous startup reason data if it was present on disk, or empty startup reason object.
*/
you need to provide a directory they can write into. So Apps's document directory would be the best (as a root) + whatever folder you want (which, based on their code, they will even create for you).
So:
NSURL* docs = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL* myCrashes = [docs URLByAppendingPathComponent:#"myCrashes" isDirectory:TRUE];
it will look something like:
file:///some/path/to/app/sandbox/data/Documents/myCrashes
Try looking up documentation for
- (NSArray<NSURL *> *)URLsForDirectory:(NSSearchPathDirectory)directory
inDomains:(NSSearchPathDomainMask)domainMask;`
That will get you the URL and check out FileManager.SearchPathDirectory enum for all the viable options:
Here's an example for getting the caches directory
NSURL* url = [[[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];`
It could be any one of the 25-26 options in SearchPathDirectory depending on where they put that stuff.
I'm making an app that uses encoding to store objects on the document directory,
On iOS Simulator, the objects are getting saved perfectly, and if i closed the app and got back to it all the data are restored with no issue.
But today i tried my app on the iPhone 5s, the objects are not getting saved when i close the app and go back to it again all the data are getting removed only on the real device, what is the problem ?
I'm using this method to get the directory path:
- (NSString *)pathForTask
{
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [documentDirectories firstObject];
return [documentDirectory stringByAppendingString:#"Tasks"];
}
Archive:
NSString *path = [self pathForTask];
[NSKeyedArchiver archiveRootObject:self.privateTasks toFile:path];
Unarchive:
NSString *path = [self pathForTask];
_privateTasks = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
The following line of code is causing your problem:
return [documentDirectory stringByAppendingString:#"Tasks"];
The results in the returned path being something like:
.../DocumentsTasks
Note the lack of a slash.
Change the line to:
return [documentDirectory stringByAppendingPathComponent:#"Tasks"];
This will return a proper path and your code will work on a device.
It works in the simulator because you end up creating a file named DocumentTasks in some folder on your computer. But on a real device, the folder that this file is trying to be written to is read-only due to sandboxing.
Try getting the documents directory using the following code instead:
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
After getting the documents directory, you can get the path to a specific file by doing:
NSURL *fileURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"[FILE NAME]"];
I'm not sure why your code doesn't work, but this is the code I use on my app and it works in the simulator and the physical device.
Frequently code that works on the sim but not on the device is caused by filename upper/lower case mismatching.
The file system in Mac OS is almost always case-insenstive. (You can use disk volumes who's file system are case sensitive in Mac OS, but they are not by default.)
The simulator runs on Mac OS. It's file system is not case sensitive. So if you save a file as "Tasks" and then load it as "tasks" it works on the sim, but not on an actual iOS device. Make sure you check really carefully for mismatched case in your filenames.
I've looked through the Apple documentation on this point and other questions here, but cannot find a means of getting a consistent path to the documents directory.
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *urls = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSURL *directory = [urls lastObject];
This produces a different path each time due to one component.
Example:
file:///var/mobile/Containers/Data/Application/CA708CF5-0E1B-414D-A795-31A8BB884BA5/Documents
Next run:
file:///var/mobile/Containers/Data/Application/2C96E341-85EF-485D-AC19-F8844B0880C3/Documents
I realize I need some kind of relative path here but I cannot figure out how to get it. How can I get to the Documents directory consistently to both write and read a file my app will produce?
The path is determined on installation. Each time you run your app in the simulator, it will be removed and reinstalled. Hence the differernt path. So you don't need to worry about this.
I am building a simple iOS app. And I need to read some data from a text file.
But I don't know where to put it.
I have tried to put it under the Debug-iphoneos or Debug-iphonesimulator. But it doesn't work.
Drag it into your project. When asked if it should be part of the app target, make sure it is. The result is that when you build the app, the file will be copied into the app bundle and thus will make its way onto the target device as part of the app, where your code can retrieve it, along these lines:
NSString* f = [[NSBundle mainBundle] pathForResource:#"myfile" ofType:#"txt"];
NSError* err = nil;
NSString* s = [NSString stringWithContentsOfFile:f
encoding:NSUTF8StringEncoding
error:&err];
The main bundle should work like others have stated, if you want to access it for testing via the documents directory for some testing or other purposes. This should give you the directory for that app:
NSLog(#"%#",[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] objectAtIndex:0]);
Resulting URL for if you decide to put it into the documents folder:
[[[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] objectAtIndex:0]URLByAppendingPathComponent:#"YOUR_FILE_NAME_HERE"] URLByAppendingPathExtension:#"txt"];
-[NSFileManager URLForDirectory:inDomain:appropriateForURL:create:error:] requires a single NSSearchPathDomainMask and returns a single URL. (The ...appropriateForURL:create:error: part is a bit confusing in documentation.)
-[NSFileManager URLsForDirectory:inDomains:] allows you to create a bit-mask for the domains parameter and returns an array of URLs.
It seems to me there is overlap between these two methods. If my goal is to get the Documents, or Library, or etc directory from an iOS app's sandbox, when should I use one over the other?
The standard way to get access to the Documents directory (or other similar directories) is code like the following:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = paths[0];
This is similar to doing:
NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSURL *documentsURL = URLs[0];
The key difference is the first gives you the path as an NSString while the second gives you the path as an NSURL.
The other method can be used by doing:
NSURL *documentsURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
You can pass NO for the Documents directory because it always exists. You should pass YES for the application support directory since it doesn't exist by default. And ideally you should not pass in nil for the error so you can see what happened if the method call returns nil.
Any of these three approaches work. Use the 1st if you want the path as a string. Use the 3rd if you want it as a URL. Use the 2nd if you have the rare need to pass in more than one domain.