Pregunta UIDocument & NSFileWrapper - NSFastEnumerationMutationHandler al cambiar el contenedor de archivos durante un guardado


tengo un UIDocument aplicación basada que utiliza NSFileWrappers para almacenar datos. El contenedor de archivos 'maestro' contiene muchos envoltorios de archivos de directorio adicionales, cada uno de los cuales representa una página diferente del documento.

Cada vez que hago un cambio en el documento mientras UIDocument está ahorrando writeContents:andAttributes:safelyToURL:forSaveOperation:error:), la aplicación se bloquea. Aquí está el rastro de la pila:

UIDocument crash stack trace

Parece claro que estoy modificando la misma instancia de contenedor de archivos que el UIDocument está enumerando más en el fondo. De hecho, comprobé que al devolver una instantánea del modelo de datos en contentsForType:error:, los envoltorios de subarchivos devueltos apuntan a los mismos objetos que los que residen actualmente (y se están editando) en el modelo de datos, y no las copias.

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

Este es el enfoque sancionado para implementar este método (de acuerdo con WWDC 2012 Session 218 - Uso de iCloud con UIDocument).

Así que supongo que la pregunta es: ¿Cómo puede ser seguro este enfoque hilo?

Es la situación de alguna manera diferente cuando el contenedor del archivo maestro fileWrappers ¿Son ellos mismos los envoltorios de archivos de directorio? Si el enfoque sancionado es incorrecto, ¿cómo debería se hará?


5
2018-03-05 19:19


origen


Respuestas:


Si está llamando a alguno de los writeContents:... Métodos, no deberías estarlo. Deberias estar llamando saveToURL:forSaveOperation:completionHandler: en lugar. los writeContents:... Los métodos son para subclasificación avanzada.

UIDocument utiliza dos subprocesos: el subproceso principal y el subproceso "UIDocument File Access" (que, si subclasifica más de UIDocument, puedes hacer cosas en via performAsynchronousFileAccessUsingBlock:).

Seguridad del hilo con UIDocument es como cualquier cosa en el Objetivo C: solo permita que el hilo que posee un objeto lo modifique. Si se está leyendo el objeto que desea cambiar, póngalo en la cola para cambiarlo una vez que se complete la escritura. Tal vez cambie un objeto diferente propiedad de su UIDocument subclase y tirarlos en un nuevo NSFileWrapper en contentsForType:error:. Pasa una copia de los archivos. NSDictionary.

NSFileWrapper en realidad carga todo el documento en la memoria. los NSFileWrapper en realidad se crea en el subproceso "UIDocument File Access" en el readFromURL:error: método, que luego se pasa a la loadFromContents:ofType:error: método. Si tiene un documento grande, esto puede tomar un tiempo.

Cuando guardas normalmente quieres dejar UIDocument decida cuándo hacer esto, y hágale saber que algo ha cambiado a través del updateChangeCount: método (param es UIDocumentChangeDone). Cuando quieres guardar algo. ahora mismo quieres usar el saveToURL:forSaveOperation:completionHandler: método.

Otra cosa a tener en cuenta es UIDocument implementa el NSFilePresenter protocolo, que define métodos para NSFileCoordinator usar. los UIDocument solo coordina la escritura en el documento raíz, no los subarchivos. Podría pensar que la coordinación de subarchivos dentro del documento podría ayudar, pero la falla que está obteniendo está relacionada con la mutación de un diccionario mientras se está iterando, por lo que no ayuda. Solo tienes que preocuparte por escribir el tuyo propio. NSFilePresenter si (1) quería recibir notificaciones de cambios en el archivo, o (2) otro objeto o aplicación estaba leyendo / escribiendo en el mismo archivo. Qué UIDocumentYa funciona bien. Usted quiere, sin embargo, utilizar NSFileCoordinator Al mover / borrar documentos enteros.


6
2018-03-12 03:24