I have a document-based iOS application with a UIDocument
subclass. I need to be able to move the file it represents on the file-system. I have considered moving it with an NSFileManager
, but this would mess up the UIDocument
's fileURL
property. Any ideas on how to solve this little conundrum?
3 Answers
This might be old but still relevant.
What you want to do is the following:
For moving: move your file using NSFileCoordinator, inside the coordinator's block, call
[fileCoordinator itemAtURL:URL willMoveToURL:toURL];
[fileManager moveItemAtURL:newURL toURL:toURL error:&moveError];
[fileCoordinator itemAtURL:URL didMoveToURL:toURL];
For deleting: overwrite your UIDocument subclass or implement the file presenter protocol method accommodatePresentedItemDeletionWithCompletionHandler:
to close the document.
- (void)accommodatePresentedItemDeletionWithCompletionHandler:(void (^)(NSError *))completionHandler;
{
[self closeWithCompletionHandler:^(BOOL success) {
NSError *err;
if (!success)
err = [NSError error]; // implement your error here if you want
completionHandler(err);
}];
}
Thus ensuring it will correctly handle being moved.

- 207
- 3
- 7
-
Those NSFileCoordinator methods are only useful for sandboxed apps. From the docs: "If your macOS app is not sandboxed, this method serves no purpose. This method is nonfunctional in iOS." – Devin McKaskle Sep 21 '21 at 17:35
You can rename a UIDocument by first closing it, and then in the completion handler, moving the file using NSFileManager. Once the file has been successfully moved, initialize a new instance of your UIDocument subclass using the new file URL:
NSURL *directoryURL = [_document.fileURL URLByDeletingLastPathComponent];
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSString *filePath = [directoryURL.path stringByAppendingPathComponent:@"NewFileName"];
[_document closeWithCompletionHandler:^(BOOL success) {
NSError *error;
if (success)
success = [fileManager moveItemAtPath:_document.fileURL.path toPath:filePath error:&error];
if (success) {
NSURL *url = [NSURL fileURLWithPath:filePath];
// I handle opening the document and updating the UI in setDocument:
self.document = [[MyDocumentSubclass alloc] initWithFileName:[url lastPathComponent] dateModified:[NSDate date] andURL:url];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"Unable to rename document" delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
[alert show];
NSLog(@"Unable to move document: %@", error);
}
}];

- 654
- 4
- 10
-
Although this will work, you're not always able to close the document before moving without violating encapsulation. – Elland Aug 21 '13 at 12:08
I found this in the UIDocument
class specification (5.1):
Implementation of
NSFilePresenter
ProtocolThe
UIDocument
class adopts theNSFilePresenter
protocol. When another client attempts to read the document of aUIDocument
-based application, that reading is suspended until theUIDocument
object is given an opportunity to save any changes made to the document.Although some implementations do nothing,
UIDocument
implements allNSFilePresenter
methods. Specifically,UIDocument
:Implements
relinquishPresentedItemToReader:
to forward the incoming block toperformAsynchronousFileAccessUsingBlock:
.Implements
relinquishPresentedItemToWriter:
to check if the file-modification date has changed; if the file is newer than before, it callsrevertToContentsOfURL:completionHandler:
with the value of thefileURL
as the URL parameter.Implements
presentedItemDidMoveToURL:
to update the document’s file URL (fileURL
).In your
UIDocument
subclass, if you override aNSFilePresenter
method you can always invoke the superclass implementation (super
).
I was hopelessly searching too and I hope the above helps. I haven't tested it yet — I'm jumping on it right now.
So basically, if I don't miss anything here, you have to move the document using NSFileManager
and then call presentedItemDidMoveToURL:
on your document. You have probably to move the file using NSFileCoordinator
, to make sure you don't get problems.
Please correct everything in this answer that's wrong. I'm still a n00b in all that stuff.

- 6,846
- 6
- 43
- 54
-
1This is the right idea, but I don't think you should be calling `presentedItemDidMoveToURL:` directly, but rather calling the file coordinator notifications. Main reason being you can have more than one file presenter open, and calling the notification methods will ensure all of them get it. – Elland Aug 21 '13 at 12:12