9

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

UIDocument每当我在保存(在)时对文档进行更改时writeContents:andAttributes:safelyToURL:forSaveOperation:error:,应用程序就会崩溃。这是堆栈跟踪:

UIDocument 崩溃堆栈跟踪

很明显,我正在修改UIDocument在后台枚举的文件包装器的同一实例。实际上,我检查了在返回数据模型的快照时contentsForType:error:,返回的子文件包装器指向与数据模型中当前驻留(和正在编辑)的对象相同的对象,而不是副本。

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

这是实施此方法的认可方法(根据WWDC 2012 Session 218 - Using iCloud with UIDocument)。

所以我想问题是:这种方法如何是线程安全的?

当主文件包装器fileWrappers本身是目录文件包装器时,情况是否有所不同?如果制裁的方法是错误的,应该怎么做?

4

2 回答 2

8

如果您正在调用任何writeContents:...方法,则不应如此。你应该打电话saveToURL:forSaveOperation:completionHandler:。这些writeContents:...方法用于高级子类化。

UIDocument使用两个线程 - 主线程和“UIDocument 文件访问”线程(如果您将更多的子类化UIDocument,您可以在 via 中执行操作performAsynchronousFileAccessUsingBlock:)。

线程安全UIDocument就像 Objective C 中的任何东西一样——只让拥有一个对象的线程修改它。如果您要更改的对象正在被读取,请在写入完成后将其排队等待更改。也许更改您的子类拥有的不同对象UIDocument并将它们拉入新NSFileWrappercontentsForType:error:. 传递 fileWrappers 的副本NSDictionary

NSFileWrapper实际上将整个文档加载到内存中。NSFileWrapper实际上是在方法中的“UIDocument 文件访问”线程中创建的,readFromURL:error:然后将其传递给loadFromContents:ofType:error:方法。如果您有一个大文件,这可能需要一段时间。

保存时,您通常希望决定何时执行此操作,并通过该方法(参数是)UIDocument让它知道某些内容已更改。当你现在想保存一些东西时,你想使用该方法。updateChangeCount:UIDocumentChangeDonesaveToURL:forSaveOperation:completionHandler:

要注意的另一件事是UIDocument实现NSFilePresenter协议,该协议定义了NSFileCoordinator要使用的方法。唯一的UIDocument坐标写入根文档,而不是子文件。您可能认为在文档中协调子文件可能会有所帮助,但是您遇到的崩溃与在迭代时更改字典有关,因此这无济于事。NSFilePresenter如果您 (1) 想要获得文件更改通知,或者 (2) 另一个对象或应用程序正在读取/写入同一个文件,您只需要担心自己编写。已经做的事情UIDocument会很好。但是,您确实希望NSFileCoordinator在移动/删除整个文档时使用。

于 2013-03-12T03:24:06.117 回答
0

我知道这是一个古老的线程,但我最近遇到了这个问题,为了帮助未来的旅行者:如果你的主文件包装器中有子目录,你还需要复制那些 NSFileWrapper (除了复制上面的根 NSFileWrapper )。

否则,当 UIDocument 后台线程在保存时枚举它们并且同时在主线程上发生修改时,可能会发生崩溃。目前尚不清楚,但这可能是 OP 遇到的问题。

另一个提示是您还需要复制子目录的 NSFileWrapper 的文件名、文件属性(可能还有首选文件名),以便增量保存工作。

HTH。

于 2019-10-16T03:14:04.217 回答