iosicloudnsfilemanageruidocumentnsfilecoordinator

Rename an iCloud document


The problem

What I have so far is code that creates a new local file and deletes the iCloud file.

Is it possible to rename an iCloud document, so that it stays in iCloud?

GarageBand can do it. It's possible to rename an iCloud song. After the rename is done, the song is still in iCloud. However GarageBand is an Apple app, so it may use private apis.

My current code:

- (void)moveFrom:(NSURL*)sourceURL
          moveTo:(NSString*)destinationName
      completion:(void (^)())completion
{
    MyDocument *document = [[MyDocument alloc] initWithFileURL:sourceURL];
    [document openWithCompletionHandler:^(BOOL success)
    {
        NSURL *fileURL = [self.localRoot URLByAppendingPathComponent:destinationName];
        DLog(@"Create %@", fileURL);
        [document saveToURL:fileURL
           forSaveOperation:UIDocumentSaveForCreating
          completionHandler:^(BOOL success)
        {
            NSLog(@"Saved %@", fileURL);
            [document closeWithCompletionHandler:^(BOOL success) {
                // Delete the old document from a secondary thread
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^()
                {
                    NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
                    [fileCoordinator coordinateWritingItemAtURL:sourceURL
                                                        options:NSFileCoordinatorWritingForDeleting
                                                          error:nil
                                                     byAccessor:^(NSURL* writingURL) {
                        NSFileManager* fileManager = [[NSFileManager alloc] init];
                        [fileManager removeItemAtURL:writingURL error:nil];
                        DLog(@"Deleted %@", sourceURL);
                        completion();
                    }];
                });
            }];
        }];
    }];
}

Update: Still no luck

I have found out that -setUbiquitous:itemAtURL:destinationURL:error: cannot be used for renaming documents.

If I invoke [setUbiquitous:NO itemAtURL:oldLocalURL destinationURL:newLocalURL error:&error] on an already local file, then:

Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)" UserInfo=0x1fdf6730 {NSURL=file://localhost/var/mobile/Applications/4BABA000-B100-49FC-B928-B0F403FC75FF/Documents/LocalDrawing.td2/, NSUnderlyingError=0x20940e80 "The operation couldn’t be completed. (LibrarianErrorDomain error 2 - Cannot disable syncing on a unsynced item.)"}

If I invoke [setUbiquitous:YES itemAtURL:oldCloudURL destinationURL:newCloudURL error:&error] on an already cloud file, then:

Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)" UserInfo=0x208e9820 {NSURL=file://localhost/var/mobile/Library/Mobile%20Documents/22DR89XVRF~com~opcoders~triangle-draw/Documents/CloudDrawing.td2/, NSUnderlyingError=0x208d45b0 "The operation couldn’t be completed. (LibrarianErrorDomain error 2 - Cannot enable syncing on a synced item.)"}

Thus -setUbiquitous:itemAtURL:destinationURL:error: cannot be used for renaming documents.


Solution

  • I have finally solved it. This is my code so far:

    - (void)_moveURL:(NSURL*)sourceURL
             destURL:(NSURL*)destinationURL
             success:(void (^)())successBlock
             failure:(void (^)(NSError *))failureBlock
    {
        NSParameterAssert(sourceURL);
        NSParameterAssert(destinationURL);
        NSParameterAssert(successBlock);
        NSParameterAssert(failureBlock);
    
        // Do the actual renaming
        __block NSError *moveError = nil;
        __block BOOL moveSuccess = NO;
        void (^accessor)(NSURL*, NSURL*) = ^(NSURL *newURL1, NSURL *newURL2) {
            NSFileManager *fileManager = [[NSFileManager alloc] init];
            moveSuccess = [fileManager moveItemAtURL:sourceURL toURL:destinationURL error:&moveError];
        };
    
        // Coordinate renaming
        NSError *coordinatorError = nil;
        NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
        [coordinator coordinateWritingItemAtURL:sourceURL
                                        options:NSFileCoordinatorWritingForMoving
                               writingItemAtURL:destinationURL
                                        options:NSFileCoordinatorWritingForReplacing
                                          error:&coordinatorError
                                     byAccessor:accessor];
        if (moveSuccess) {
            successBlock();
            return;
        }
        if (moveError) {
            failureBlock(moveError);
            return;
        }
        if (coordinatorError) {
            failureBlock(coordinatorError);
            return;
        }
        NSAssert(NO, @"should not happen");
    }