UIDocument 打开/关闭行为

Posted

技术标签:

【中文标题】UIDocument 打开/关闭行为【英文标题】:UIDocument open/close behavior 【发布时间】:2012-06-25 06:32:17 【问题描述】:

我有一个基于 UIDocument 的应用程序,但没有 iCloud 支持。用户可以创建文档,并将它们保存到应用的 Document 目录中。

我还创建了一些“示例”文档,并将它们与应用程序包一起传递。我希望用户能够像打开自己的文档一样打开示例文档:

NSArray *samplesContent = [[NSBundle mainBundle] URLsForResourcesWithExtension:@"doco" subdirectory:@"Samples"];

for (NSURL *sampleURL in samplesContent) 
    Doco *doco = [[Doco alloc] initWithFileURL:sampleURL];
    [doco disableEditing];

    [doco openWithCompletionHandler:^(BOOL success) 
        if (success) 
            [self.docos addObject:doco];

            if (self.docos.count >= samplesContent.count) 
                [self.tableView reloadData];
            
         else DLog(@"Failed to open %@", [sampleURL pathExtension]);
     ];

我看到的是这样的:

    viewDidLoad 上,docs 数组将填充示例文档,并在应用程序首次启动时显示在 tableView 中。这里没有问题,一切都很顺利和美好。

    然后我使用以下代码退出视图以关闭所有打开的文档:

    int count = 0;
    
    for (Doco *doco in self.docos) 
        if (doco.documentState == UIDocumentStateNormal) 
            [doco closeWithCompletionHandler:nil];
            count++;
        
    
    
    DLog(@"Closed %i docs", count);
    

    当我再次打开视图时,应该再次填充文档数组并重新填充 tableView,但没有任何反应。

下面的完成处理程序永远不会被调用,尽管 URL 指向同一个文件并且它是有效的:

[doco openWithCompletionHandler:^(BOOL success) 

对于存储在 Documents 中的用户生成的文档,我没有这个问题,所以我的假设是它与自动保存有关,它在只读包上被调用并失败

但我有点卡在这部分,任何帮助将不胜感激。

【问题讨论】:

认为一个有效的解决方法是将所有示例文档复制到文档中,然后从那里打开它们......但是这样我就不会学到任何新东西:) 我更愿意理解这个问题, 为所有帮助的 cmets 干杯! 检查 [doco closeWithCompletionHandler:nil] 的完成情况。文档关闭成功了吗? 刚刚检查过,它根本没有被调用......因为我在关闭所有文档之前关闭了视图控制器。现在我看到它们无法关闭,因为它正在尝试写入 Bundle,但是它们再次成功打开.. 我收到了这个Foundation called mkdir("/var/mobile/Applications/BBBAA4C4-4824-4E67-86F4-34FC19AF1827/Doco.app/Samples/(A Document Being Saved By Doco)"), it didn't return 0, and errno was set to 1.,因此关闭不成功。 我的示例文档在我不知情的情况下进行了更新,因此它试图保存更改失败...现在我确保它没有得到更新并且它没有问题地关闭。重新加载它们再次工作得又快又好。看起来问题已解决。 【参考方案1】:

问题已经确定,但我认为值得描述几个简单的解决方案,因为在应用程序包中包含示例文档并不少见。

所以问题是示例文档在关闭时尝试保存更改,但在只读应用程序包中保存无法成功。

我认为这里有两个主要的解决方案:

    将示例文档复制到 Documents 目录中,可以将其与任何其他文档一样处理并成功保存(如果您希望保存用户对示例文档的编辑,请使用此方法)。

    防止文档尝试保存(对于只读示例文档)。

所以这里有一些简单的例子......


1。将示例文档复制到 Documents 目录中

在首次启动时(或者实际上每当您决定“刷新”示例文档时),使用NSFileManager 将文件复制到位:

- (void)refreshSampleDocuments

    NSArray *sampleFromURLs = [[NSBundle mainBundle] URLsForResourcesWithExtension:@"doc" subdirectory:@"Samples"];

    for (NSURL *sampleFromURL in sampleFromURLs) 

        NSString *sampleFilename = [sampleFromURL lastPathComponent];
        NSURL *sampleToURL = [[self documentsDirectoryURL] URLByAppendingPathComponent:sampleFilename];

        // ...
        // Do some checks to make sure you won't write over any user documents!
        // ....

        NSError *error;
        BOOL copySuccessful = [[NSFileManager defaultManager] copyItemAtURL:sampleFromURL toURL:sampleToURL error:&error];

        if (!copySuccessful) 
            // Handle error...
        
    


2。阻止示例文档尝试保存

这种方法要简单得多(对于只读文档),并且比试图阻止文档中可能出现的更新更容易。

当在UIDocument 上调用closeWithCompletionHandler: 时,将调用autosaveWithCompletionHandler: 以确保在关闭之前保存文档文件。这反过来又调用hasUnsavedChanges 来决定是否需要保存。因此,如果hasUnsavedChanges 返回NO,那么任何 调用自动保存机制都将导致不会写出任何更改。

(注意手动调用 saveToURL:forSaveOperation:completionHandler: 仍然会强制保存,无论 hasUnsavedChanges 返回什么。)

因此,在您的 UIDocument 子类中,如果文档是只读的,则覆盖 hasUnsavedChanges 以返回 NO

@interface MyDocument : UIDocument

@property(nonatomic, getter = isReadOnly) BOOL readOnly;

@end


@implementation MyDocument

- (BOOL)hasUnsavedChanges

    return [self isReadOnly] ? NO : [super hasUnsavedChanges];


@end

【讨论】:

【参考方案2】:

如果 UIDocument 已更新,它将尝试在关闭时保存更改。 由于UIDocument 是从只读包加载的,我必须确保它不会被更新,否则关闭块返回success=NO,并且文档没有关闭...

【讨论】:

以上是关于UIDocument 打开/关闭行为的主要内容,如果未能解决你的问题,请参考以下文章

UIDocument 无法再次关闭?

在哪里存储 UIDocument 的预览?

尝试关闭 UIDocument 时防止崩溃

使用 setUbiquitous 为 UIDocument 文件关闭 iCloud 同步时出错(LibrarianErrorDomain 错误 2)

文档关闭后调用的 Swift UIDocument 自动保存并且类不会取消初始化

同步打开 UIDocument