UIDocument和NSFileWrapper - NSFastEnumerationMutationHandler在保存期间更改文件包装器

Stu*_*art 6 save thread-safety nsfilewrapper ios uidocument

我有一个UIDocument基于应用程序,使用NSFileWrappers来存储数据.'master'文件包装器包含许多其他目录文件包装器,每个包装器代表文档的不同页面.

每当我在UIDocument保存(in 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]];
}
Run Code Online (Sandbox Code Playgroud)

这是实施此方法的认可方法(根据WWDC 2012会议218 - 使用带有UIDocument的iCloud).

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

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

Luk*_*uke 7

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

UIDocument使用两个线程 - 主线程和"UIDocument文件访问"线程(如果你继承了更多的线程UIDocument,你可以在via中做事performAsynchronousFileAccessUsingBlock:).

线程安全与UIDocumentObjective C中的任何内容类似 - 只允许拥有对象的线程修改它.如果正在读取要更改的对象,请在写入完成后将其排队以进行更改.也许更改UIDocument子类拥有的不同对象并将其拉入新的对象NSFileWrappercontentsForType:error:.传递fileWrappers的副本NSDictionary.

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

当您节省通常想让UIDocument决定何时做到这一点,让它知道事情已经通过改变updateChangeCount:方法(参数是UIDocumentChangeDone).当你想要保存的东西,现在你要使用的saveToURL:forSaveOperation:completionHandler:方法.

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