Hello there. I want to create a file in a public folder (where it could be seen by user, and the file could be read again.
To achieve that, I use document picker, and set the document type to "public.folder" and inMode "UIDocumentPickerModeOpen".
After user opens the document picker and selects the desired folder, in "didPickDocumentsAtURLs" callback I get the NSUrl object, which has permissions to modify the file at that url (in this case, it's an url to a folder).
There is my issue. I have the url with access permission to a folder, however, to create a file I ussualy need to have the filename.extension in the url. If I were to modify the NSUrl object I've received from the document picker, or convert it to NSString, my guess is I lose the access permission and "createFileAtPath" method always fails.
Any leads would be kindly appreciated!
Hello eskimo!
Thank you for the advices, they are super helpful and I'll be sure to implement them in my code!
However, I won't accept your answer, since the issue in my case was, that I was trying to call startAccessingSecurityScopedResource
with a modified url (the folder that the user chose + NewFileName.extension). It kept returning false, no matter how I've modified the URL.
What worked for me, was calling startAccessingSecurityScopedResource
with an unmodified folder url, that I receive from document picker.
Here I will leave a fully working example for future readers, to make their life easier:
- (void)openDocumentPicker
{
//This is needed, when using this code on QT!
//Find the current app window, and its view controller object
/*
UIApplication* app = [UIApplication sharedApplication];
UIWindow* rootWindow = app.windows[0];
UIViewController* rootViewController = rootWindow.rootViewController;
*/
//Initialize the document picker. Set appropriate document types
//When reading: use document type of the file, that you're going to read
//When writing into a new file: use @"public.folder" to select a folder, where your new file will be created
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.folder"] inMode:UIDocumentPickerModeOpen];
//Assigning the delegate, connects the document picker object with callbacks, defined in this object
documentPicker.delegate = self;
documentPicker.modalPresentationStyle = UIModalPresentationFormSheet;
//In this case we're using self. If using on QT, use the rootViewController we've found before
[self presentViewController:documentPicker animated:YES completion:nil];
}
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls
{
//If we come here, user successfully picked a single file/folder
//When selecting a folder, we need to start accessing the folder itself, instead of the specific file we're going to create
if ( [urls[0] startAccessingSecurityScopedResource] ) //Let the os know we're going use this resource
{
//Write file case ---
//Construct the url, that we're going to be using: folder the user chose + add the new FileName.extension
NSURL *destURLPath = [urls[0] URLByAppendingPathComponent:@"Test.txt"];
NSString *dataToWrite = @"This text is going into the file!";
NSError *error = nil;
//Write the data, thus creating a new file. Save the new path if operation succeeds
if( ![dataToWrite writeToURL:destURLPath atomically:true encoding:NSUTF8StringEncoding error:&error] )
NSLog(@"%@",[error localizedDescription]);
//Read file case ---
NSData *fileData = [NSData dataWithContentsOfURL:destURLPath options:NSDataReadingUncached error:&error];
if( fileData == nil )
NSLog(@"%@",[error localizedDescription]);
[urls[0] stopAccessingSecurityScopedResource];
}
else
{
NSLog(@"startAccessingSecurityScopedResource failed");
}
}