gpt4 book ai didi

ios - UIDocument 和 NSFileWrapper - 尽管有增量更改,但大型文件需要很长时间才能保存

转载 作者:可可西里 更新时间:2023-11-01 03:33:10 24 4
gpt4 key购买 nike

我有一个基于 UIDocument 的应用程序,它使用 NSFileWrapper 来存储数据。 “主”文件包装器包含许多其他目录文件包装器,每个包装器代表文档的不同页面。

当保存一个只有一小部分页面被修改的大型文档时,UIDocument 会在后台花费很长时间写入更改(在 writeContents:andAttributes:safelyToURL 中: forSaveOperation:错误:)。当然,它应该只写出对文件包装器的这一小改动……为什么要花这么长时间?

我的 contentsForType:error: 覆盖返回一个新的目录文件包装器,其中包含主文件包装器的内容(la WWDC 2012 Session 218 - Using iCloud with UIDocument ):

- (id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
if (!_fileWrapper) {
[self setupEmptyDocument];
}
return [[NSFileWrapper alloc] initDirectoryWithFileWrappers:[_fileWrapper fileWrappers]];
}

这是来自 Time Profiler 的堆栈跟踪的可爱图片:

UIDocument slow write stack trace

顺便说一下,它表示在该工作线程中需要保存 ~1.6s - 在实际运行时间中,这相当于大约 8 秒。


编辑:

有什么方法可以检查文件包装器是否需要写入磁盘?这样我就可以确认我没有以某种方式做一些奇怪的事情,比如在我进行小改动时更新每个子文件包装器(尽管我确定我没有...)。


编辑:

我进一步研究了 CloudNotes 示例应用程序,看来 NSFileWrapper 确实实现了增量保存,至少在那种情况下是这样!我通过初始化一个包含 100 个注释的文档来测试它,每个注释包含大约 5MB 的数据。我在这里和那里做了一个小的编辑(对 TextView 的单个字符更改将文档标记为需要保存),并大致记录了每次保存花费的时间。测试相对粗糙(在模拟器上运行),但结果是这样的:

  • 第一次写入:~8000ms
  • 第二次写入:~4000ms
  • 第三次写入:~300ms
  • 所有后续写入:~40ms

显然有很多因素会影响它花费的时间,特别是因为它在后台线程中使用文件协调来节省时间,但总的来说趋势似乎总是这种指数衰减,直到所有写入都变得非常快。

但我仍在尝试弄清楚为什么我的应用程序中没有发生这种情况。对于大型多页文档(很大,但仍然比我上面执行的 CloudNotes 测试的文档小很多倍),用户可能需要等待很多秒才能关闭文档。我不想为实际上应该是瞬时的事情设置一个微调器。

最佳答案

NSFileWrapper 实际上是将整个文档加载到内存中。因此,对于 UIDocument,使用 NSFileWrapper 实际上对大型文档不利。该文档使您认为它会进行增量保存,但就我而言,它似乎并没有这样做。

UIDocument 不仅限于 NSFileWrapperNSData。您可以使用自己的自定义类,只需重写某些方法即可。我最终编写了自己的文件包装器类,它仅引用磁盘上的文件并按需读/写单个文件。

这是我的 UIDocument 类使用自定义文件包装器的样子:

@implementation LSDocument

- (BOOL)writeContents:(LSFileWrapper *)contents
andAttributes:(NSDictionary *)additionalFileAttributes
safelyToURL:(NSURL *)url
forSaveOperation:(UIDocumentSaveOperation)saveOperation
error:(NSError *__autoreleasing *)outError
{
return [contents writeUpdatesToURL:self.fileURL error:outError];
}

- (BOOL)readFromURL:(NSURL *)url error:(NSError *__autoreleasing *)outError
{
__block LSFileWrapper *wrapper = [[LSFileWrapper alloc] initWithURL:url isDirectory:NO];
__block BOOL result;
dispatch_sync(dispatch_get_main_queue(), ^(void) {
result = [self loadFromContents:wrapper
ofType:self.fileType
error:outError];
});
[wrapper loadCache];
return result;
}

@end

我将其用作基类并将其子类化用于其他项目。它应该让您了解必须执行哪些操作才能集成自定义文件包装器类。

关于ios - UIDocument 和 NSFileWrapper - 尽管有增量更改,但大型文件需要很长时间才能保存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15230818/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com