Hi
I would like to get your feedback on best practices with opening, closing, saving UIDocuments.
I have a viewController that shows the content of an UIDocument and which allows the user to rename documents and create new ones.
UIDocument does everything via completionHandlers to avoid blocking the UI. But if I want to rename a document, I first have a) to close it, b) rename it (via NSFileManager), c) open the new document, d) reload the view.
Same with a new document: a) close old document, b) create new document, c) open new document, d) reload the view.
But that is when everything works fine. If something goes wrong, the stack of completion handlers just keeps getting deeper.
I understand it can't work the same way as NSDocument because of iCloud and network delays.
But this many levels of if statements just "smells" bad. So what's the best approach?
ViewController, after returning from an UIActionSheet:
and in MyCloudManager
I would like to get your feedback on best practices with opening, closing, saving UIDocuments.
I have a viewController that shows the content of an UIDocument and which allows the user to rename documents and create new ones.
UIDocument does everything via completionHandlers to avoid blocking the UI. But if I want to rename a document, I first have a) to close it, b) rename it (via NSFileManager), c) open the new document, d) reload the view.
Same with a new document: a) close old document, b) create new document, c) open new document, d) reload the view.
But that is when everything works fine. If something goes wrong, the stack of completion handlers just keeps getting deeper.
I understand it can't work the same way as NSDocument because of iCloud and network delays.
But this many levels of if statements just "smells" bad. So what's the best approach?
ViewController, after returning from an UIActionSheet:
Code:
switch (buttonIndex)
{
case 0: //destructive
//todo: delete current document and present new document
break;
case 1:
{
[[MyCloudManager sharedCloudManager] renameDocument:[self currentDocument]
completionHandler:^(BOOL succes, id renamedDocument) {
if (succes)
{
[self setCurrentDocument:renamedDocument];//will open the renamed document
}
}];
}
break;
case 2:
{
double delayInSeconds = 0.3;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//todo: notify user that it's going to take awhile?
});
[[self currentDocument] closeWithCompletionHandler:^(BOOL success) {
if (success)
{
[[MyCloudManager sharedCloudManager] newUntitledDocument:NSStringFromClass([[self currentDocument] class])
completionHandler:^(BOOL succes, id newDocument) {
if (success)
{
[self setCurrentDocument:newDocument];//will open the new document
}
else
{
[[self currentDocument] openWithCompletionHandler^(BOOL success) {
if (!success)
{
//tell the user the old file couldn't be reopenend
}
}];//reopen the old document
}
}];
}
}];
and in MyCloudManager
Code:
-(void) renameDocument:(id) document
completionHandler:(void(^)(BOOL succes, id renamedDocument)) completionHandler
{
_currentDocument = document;
_renameBlock = completionHandler;
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[document localizedName]
message:NSLocalizedString(@"Enter new name",@"alert message: enter new name for current document")
delegate:self
cancelButtonTitle:NSLocalizedString(@"Cancel",@"cancel rename current document")
otherButtonTitles:NSLocalizedString(@"rename", @"rename current document"), nil];
[alertView setAlertViewStyle:UIAlertViewStylePlainTextInput];
[alertView show];
}
-(void) alertView:(UIAlertView *) alertView
clickedButtonAtIndex:(NSInteger) buttonIndex
{
if (buttonIndex == 1)
{
void (^moveBlock)(NSString *) = ^(NSString *name){
NSURL *currentURL = [_currentDocument fileURL];
NSURL *baseURL = [currentURL URLByDeletingLastPathComponent];
NSURL *newURL = [[baseURL URLByAppendingPathComponent:name] URLByAppendingPathExtension:[currentURL pathExtension]];
NSError *error;
[[NSFileManager defaultManager] moveItemAtURL:currentURL
toURL:newURL
error:&error];
id newDocument = [(UIDocument *)[[_currentDocument class] alloc] initWithFileURL:newURL];
_renameBlock((error == nil),newDocument);
};
//todo: don't overwrite existing files
//if (!([baseURL checkResourceIsReachableAndReturnError:nil] && ![newURL checkResourceIsReachableAndReturnError:nil]))
NSString *newName = [[alertView textFieldAtIndex:0] text];
if ([_currentDocument documentState] == UIDocumentStateClosed)
{
moveBlock(newName);
}
else if ([_currentDocument documentState] == UIDocumentStateNormal)
{
[_currentDocument closeWithCompletionHandler:^(BOOL success) {
moveBlock(newName);
}];
}
}
else
{
_renameBlock(NO,nil);//user didn't rename document
}
}