UIDocumentPicker Error on accession selected file

I have an issue on importing files into my app when selected by the user through UIDocumentPickerViewController. The error I get is: Error Domain=NSPOSIXErrorDomain Code=13 "Permission denied". I'm testing on iPhone 11 with iOS 13.5.1.

This is my implementation:

Code Block
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]){
        
        urls.forEach { (url) in
            
            let access = url.startAccessingSecurityScopedResource()
            var error: NSError? = nil
            NSFileCoordinator().coordinate(readingItemAt: url, error: &error) { (coorURL) in
            do{
                    let gZippedData = try Data(contentsOf: url)
                    print(gZippedData)
                    if access{
                        url.stopAccessingSecurityScopedResource()
                    }
                }catch{
                    print(error.localizedDescription)
                }
                    }
                }
            }
        }
    }


The value of access is true. why I can't access the file? what am I missing?

Thank you for your help.
This is working for me. There’s a copy of my test code below. I’m running this on 13.5.1 choosing a file that I saved On My iPhone using Notes. I then copied the file to the root of my iCloud Drive and it works there too.

Which call is generating the error? The NSFileCoordinator? Or the Data(contentsOf:)?

The actual error is interesting. Error code 13 is EACCES, which is usually returned when the access is blocked by the file system itself. When the access is blocked by the sandbox, you usually get back EPERM.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"



Code Block
private func test() {
let picker = UIDocumentPickerViewController(documentTypes: ["public.text"], in: .open)
picker.delegate = self
self.present(picker, animated: true, completion: nil)
self.tableView.deselectRow(at: indexPath, animated: true)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
let url = urls.first!
guard url.startAccessingSecurityScopedResource() else {
print("can't access")
return
}
defer { url.stopAccessingSecurityScopedResource() }
do {
let text = try String(contentsOf: url, encoding: .utf8)
print(text)
} catch {
print(error)
}
}

@eskimo The file I'm trying to access is a custom file (created with UIDocument and NSFileWrapper) from another applications of mine. I added the support to this new app I'm developing to open those files, but even through the "open in" functionality directly from File app I get always the same error. I checked the code of the other project but I don't see any restriction created directly by me. From the other app I can zip and export the file, in that case my new app can open the exported file without any issue.

There is something I'm missing or that I'm not aware of?

Here there is the code from the other project, this is from the UIDocument subclass:
Code Block
-(BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError *autoreleasing *)outError{
    _fileWrapper = (NSFileWrapper*)contents;
    // The rest will be lazy loaded inside getter methods
    return YES;
}
-(id)contentsForType:(NSString *)typeName error:(NSError *autoreleasing *)outError{
    if (_fileWrapper == nil) {
        NSLog(@"NIL WRAPPER");
        _fileWrapper = [[NSFileWrapper alloc]initDirectoryWithFileWrappers:nil];
    }
    NSDictionary *fileWrappers = [_fileWrapper fileWrappers];
    [self encodeString:_name forKey:kName insideDictionary:fileWrappers];
//all other property of the document
    return _fileWrapper;
}
//pragma mark - HELPERs
-(void)encodeString:(NSString*)string forKey:(NSString*)key insideDictionary:(NSDictionary*)wrapperDic{
    if (([wrapperDic objectForKey:key] == nil) && (string != nil)) {
        NSData *textData = [string dataUsingEncoding:NSUTF8StringEncoding];
        NSFileWrapper *textFileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:textData];
        [textFileWrapper setPreferredFilename:key];
        [_fileWrapper addFileWrapper:textFileWrapper];
    }
}
-(void)encodeData:(NSData*)imageData forKey:(NSString*)key insideDictionary:(NSDictionary*)wrapperDic{
    if (([wrapperDic objectForKey:key] == nil) && (imageData != nil)) {
        @autoreleasepool {
            NSFileWrapper *imageFileWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:imageData];
            [imageFileWrapper setPreferredFilename:key];
            [_fileWrapper addFileWrapper:imageFileWrapper];
        }
    }
}


and this is the file creation:

Code Block
RecipeDocument* newDoc = [[RecipeDocument alloc]initWithFileURL:newURL];
    newDoc.name = recipe.name;
//all other property of the document
    [newDoc saveToURL:newURL
     forSaveOperation:UIDocumentSaveForCreating
    completionHandler:^(BOOL success) {


this is the code that moves the file to iCloud:

Code Block
-(void)moveFileToiCloud:(RecipeDocument *)fileToMove {
    NSURL *sourceURL = fileToMove.fileURL;
    NSString *destinationFileName = fileToMove.fileURL.lastPathComponent;
    NSURL *destinationURL = [[[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]URLByAppendingPathComponent:@"Documents"] URLByAppendingPathComponent:destinationFileName];
    if ([[NSFileManager defaultManager]fileExistsAtPath:[NSString stringWithFormat:@"%@",destinationURL]]) {
        NSLog(@"FILE EXIST");
        //Check per sapere se esiste già un file in cloud, nel caso cancello quello in locale
        RecipeDocument* check = [[RecipeDocument alloc]initWithFileURL:destinationURL];
        [check openWithCompletionHandler:^(BOOL success) {
            if (success) {
                [self deleteRecipe:[[RecipeModel alloc]initWithDocument:fileToMove atURL:sourceURL] docAtURL:sourceURL];
                return;
            }
        }];
    }
    dispatch_queue_t q_default;
    q_default = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(q_default, ^(void) {
        NSFileManager *fileManager = [[NSFileManager alloc] init];
        NSError *error = nil;
        BOOL success = [fileManager setUbiquitous:YES
                                        itemAtURL:sourceURL
                                   destinationURL:destinationURL
                                            error:&error];
        dispatch_queue_t q_main = dispatch_get_main_queue();
        dispatch_async(q_main, ^(void) {
         if (success) {
                NSLog(@"SUCCESS to move file to iCloud: %@", fileToMove.name);
            }
            if (!success) {
                NSLog(@"FAILED to move file to iCloud: %@", fileToMove.name);
            }
        });
    });
}


Thank you for your help.
Unfortunately that’s way too complex for me to tackle in the context of DevForums. My advice: Open a DTS tech support incident so that I, or more likely one of my colleagues, can offer you one-on-one help.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"

let picker = UIDocumentPickerViewController(documentTypes: ["public.text"], in: .import) notice that you should use .import and then the file will copy to you tmp/${bundle id}-Inbox/ folder, then you can do anything to it

UIDocumentPicker Error on accession selected file
 
 
Q