Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Renaming a UIDocument in iCloud

I'm struggling to figure out how to rename an instance of a UIDocument subclass in an iCloud folder. I've tried saving the document with the new URL…

func renameDocument(to name: String) {

    let targetURL = document.fileURL.deletingLastPathComponent().appendingPathComponent(name)
        .appendingPathExtension("<extension>")

    document.save(to: targetURL, for: .forCreating) { success in
        guard success else {
            // This always fails
            return
        }
        // Success
    }
}

…but this fails with…

Error Domain=NSCocoaErrorDomain Code=513 "“<new-file-name>” couldn’t be moved because you don’t have permission to access “<folder>”." UserInfo={NSSourceFilePathErrorKey=/private/var/mobile/Containers/Data/Application/1A9ACC2B-81EF-4EC9-940E-1C129BDB1914/tmp/(A Document Being Saved By My App)/<new-file-name>, NSUserStringVariant=( Move ), NSDestinationFilePath=/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/<folder>/<new-file-name>, NSFilePath=/private/var/mobile/Containers/Data/Application/1A9ACC2B-81EF-4EC9-940E-1C129BDB1914/tmp/(A Document Being Saved By My App)/<new-file-name>, NSUnderlyingError=0x1c4e54280 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

…and just a simple move…

func renameDocument(to name: String) {
    let targetURL = document.fileURL.deletingLastPathComponent().appendingPathComponent(name)
        .appendingPathExtension("<extension>")

    do {
        try FileManager.default.moveItem(at: document.fileURL, to: targetURL)
    } catch {
        // This always fails
    }        
    // Success
}

…which fails with…

Error Domain=NSCocoaErrorDomain Code=513 "“<old-file-name>” couldn’t be moved because you don’t have permission to access “<folder>”." UserInfo={NSSourceFilePathErrorKey=/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/<folder>/<old-file-name>, NSUserStringVariant=( Move ), NSDestinationFilePath=/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/<folder>/<new-file-name>, NSFilePath=/private/var/mobile/Library/Mobile Documents/com~apple~CloudDocs/<folder>/<old-file-name>, NSUnderlyingError=0x1c4c4d8c0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

Both of these work fine for local files, and renaming iCloud files works OK in the UIDocumentBrowserViewController root view controller.

My guess is that there's some permission missing somewhere that allows the app to write to iCloud folders.

For info, the info.plist contains all the following keys…

  • LSSupportsOpeningDocumentsInPlace
  • NSExtensionFileProviderSupportsEnumeration
  • UISupportsDocumentBrowser
like image 964
Ashley Mills Avatar asked Oct 17 '22 05:10

Ashley Mills


1 Answers

Are you doing this in the context of NSFileCoordinator? This is required. You shouldn't need any info.plist settings apart from NSUbiquitousContainers.

Here is my code for renaming iCloud documents:

///
/// move cloudFile within same store - show errors
///
- (void)moveCloudFile:(NSURL *)url toUrl:(NSURL *)newURL
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
    ^{
        NSError *coordinationError;
        NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];

        [coordinator coordinateWritingItemAtURL:url    options:NSFileCoordinatorWritingForMoving
                               writingItemAtURL:newURL options:NSFileCoordinatorWritingForReplacing
                                                       error:&coordinationError
                                     byAccessor:
        ^(NSURL *readingURL, NSURL  *writingURL){
            if ([self moveFile:readingURL toUrl:writingURL])
                 [coordinator itemAtURL:readingURL didMoveToURL:writingURL];
        }];
        if (coordinationError) {
            MRLOG(@"Coordination error: %@", coordinationError);
            [(SSApplication *)SSApplication.sharedApplication fileErrorAlert:coordinationError];
        }
    });
}

///
///
/// move file within same store - show errors
///
- (BOOL)moveFile:(NSURL *)url toUrl:(NSURL *)newURL
{
    NSFileManager *manager = NSFileManager.defaultManager;
    NSError *error;

    if ([manager fileExistsAtPath:newURL.path])
        [self removeFile:newURL];

    if ([manager moveItemAtURL:url toURL:newURL error:&error] == NO) {
        MRLOG(@"Move failed: %@", error);
        [(SSApplication *)SSApplication.sharedApplication fileErrorAlert:error];
        return NO;
    }
    return YES;
}
like image 87
MichaelR Avatar answered Nov 15 '22 06:11

MichaelR