【问题标题】:What is the proper way to move a UIDocument to a new location on the file-system将 UIDocument 移动到文件系统上的新位置的正确方法是什么
【发布时间】:2012-01-07 05:18:27
【问题描述】:

我有一个带有UIDocument 子类的基于文档的iOS 应用程序。我需要能够在文件系统上移动它代表的文件。我考虑过用NSFileManager 移动它,但这会弄乱UIDocument 的fileURL 属性。关于如何解决这个小难题的任何想法?

【问题讨论】:

    标签: ios5 filesystems uikit nsfilemanager uidocument


    【解决方案1】:

    这可能是旧的,但仍然相关。

    你想要做的是:

    对于移动:使用 NSFileCoordinator 移动文件,在协调器块内调用

    [fileCoordinator itemAtURL:URL willMoveToURL:toURL];
    [fileManager moveItemAtURL:newURL toURL:toURL error:&moveError];
    [fileCoordinator itemAtURL:URL didMoveToURL:toURL];
    

    对于删除:覆盖您的 UIDocument 子类或实现文件呈现器协议方法accommodatePresentedItemDeletionWithCompletionHandler: 以关闭文档。

    - (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);
    }];
    }
    

    从而确保它能够正确处理被移动。

    【讨论】:

    • 那些 NSFileCoordinator 方法只对沙盒应用有用。来自文档:“如果您的 macOS 应用程序没有被沙盒化,则此方法无用。此方法在 iOS 中不起作用。”
    【解决方案2】:

    您可以通过首先关闭 UIDocument 来重命名它,然后在完成处理程序中使用 NSFileManager 移动文件。成功移动文件后,使用新文件 URL 初始化 UIDocument 子类的新实例:

    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);
        }
    }];
    

    【讨论】:

    • 虽然这可行,但您并不总是能够在不违反封装的情况下在移动之前关闭文档。
    【解决方案3】:

    我在 UIDocument 类规范 (5.1) 中找到了这个:

    NSFilePresenter 协议的实现

    UIDocument 类采用NSFilePresenter 协议。当另一个客户端尝试读取基于UIDocument 的应用程序的文档时,该读取将暂停,直到UIDocument 对象有机会保存对文档所做的任何更改。

    虽然有些实现什么都不做,UIDocument 实现了所有NSFilePresenter 方法。具体来说,UIDocument:

    实现relinquishPresentedItemToReader: 将传入的块转发到performAsynchronousFileAccessUsingBlock:。

    实现relinquishPresentedItemToWriter: 以检查文件修改日期是否已更改;如果文件比以前更新,它会调用revertToContentsOfURL:completionHandler:,并将fileURL 的值作为URL 参数。

    实现 presentedItemDidMoveToURL: 以更新文档的文件 URL (fileURL)。

    在您的 UIDocument 子类中,如果您重写 NSFilePresenter 方法,您始终可以调用超类实现 (super)。

    我也在绝望地搜索,希望以上内容有所帮助。我还没有测试它——我现在就开始。

    所以基本上,如果我在这里没有遗漏任何内容,您必须使用NSFileManager 移动文档,然后在您的文档上调用presentedItemDidMoveToURL:。您可能必须使用NSFileCoordinator 移动文件,以确保您不会遇到问题。

    请更正此答案中所有错误的内容。在所有这些方面,我仍然是一个 n00b。

    【讨论】:

    • 这是正确的想法,但我认为您不应该直接调用presentedItemDidMoveToURL:,而是调用文件协调器通知。主要原因是您可以打开多个文件演示者,并且调用通知方法将确保所有人都得到它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多