ios escribir en el disco en el hilo de background

Actualmente estoy escribiendo algunos files en el disco en el subprocess de background simplemente llamando

dispatch_async(my_queue,^{ [self writeToRoot:filename data:data]; }; - (BOOL)writeToRoot:(NSString *)path data:(NSData *)content { NSString *fullPath = [[self rootPath] stringByAppendingPathComponent:path]; NSString *pathWithoutFile = [fullPath stringByDeletingLastPathComponent]; BOOL directoryExists = [[NSFileManager defaultManager] fileExistsAtPath:pathWithoutFile]; if (!directoryExists) { NSError *error = nil; [[NSFileManager defaultManager] createDirectoryAtPath:pathWithoutFile withIntermediateDirectories:YES attributes:nil error:&error]; NSParameterAssert(error == nil); } return [content writeToFile:fullPath atomically:NO]; } 

Estoy haciendo esto para que no bloquee el hilo principal. Mi pregunta es cómo garantizar la security de los hilos. mientras se lleva a cabo esta operación en segundo plano, qué sucede cuando bash leer el file desde el disco llamando al:

 [NSData dataWithContentsOfFile:fullPath]; 

¿Se corromperá el contenido? O la operación de escritura bloqueará el file y la operación de lectura esperará hasta que se complete la escritura?

Estaría inclinado a my_queue su operación de lectura a my_queue para garantizar la security de los hilos (suponiendo que sea una queue de serie). También podría usar cualquiera de las diversas herramientas de synchronization (como lockings o directiva @synchronized ), pero dado que ya tiene configurada su queue para la interacción del file, es probable que la utilización de esa queue de serie sea lo más fácil.

Esta técnica, de utilizar una queue para coordinar la interacción con un recurso compartido, se discute en la sección Eliminando el código basado en locking de la Guía de progtwigción de concurrency.


Por cierto, si está guardando en una queue de background (lo que significa que la operación de save es presumiblemente lo suficientemente lenta como para justificar hacerlo en segundo plano), podría ser prudente asegurarse de que solicita un poco de time para completar la operación en caso de que la aplicación, en sí misma, se interrumpa (es decir, el usuario pulsa el button de inicio físico, entra una llamada, etc.) mientras la operación de save está en progreso. Para ello, llame a beginBackgroundTaskWithExpirationHandler antes de enviar la operación de salvar y llame a endBackgroundTask cuando haya terminado:

 UIApplication *application = [UIApplication shanetworkingApplication]; // get background task identifier before you dispatch the save operation to the background UIBackgroundTaskIdentifier __block task = [application beginBackgroundTaskWithExpirationHandler:^{ if (task != UIBackgroundTaskInvalid) { [application endBackgroundTask:task]; task = UIBackgroundTaskInvalid; } }]; // now dispatch the save operation dispatch_async(my_queue, ^{ // do the save operation here // now tell the OS that you're done if (task != UIBackgroundTaskInvalid) { [application endBackgroundTask:task]; task = UIBackgroundTaskInvalid; } }); 

Esto asegurará que su operación de salvar tenga una oportunidad de luchar para completar con éxito, incluso si la aplicación se interrumpe.

Y, como señala Jsdodgers, probablemente también quiera realizar una escritura atómica.

Como su código es ahora mismo, sí habrá un problema. Esto se debe a que lo está configurando para que no se transfiera de forma atómica:

 return [content writeToFile:fullPath atomically:NO]; 

Lo que significa atómicamente es que, en lugar de eliminar el file y comenzar la escritura, escribe el file en una location de file separada y temporal. Una vez que el file está completamente escrito, entonces elimina la versión anterior del file (si existía) y cambia el nombre del file nuevo por el nombre correcto. Si la transferencia no se completa, no ocurrirá nada y el file temporal solo debería eliminarse.

Por lo tanto, si cambia atómicamente en esa línea a YES , la llamada a esos datos devolverá los datos antiguos hasta que se complete el guardado, y en cualquier momento después obtendrá los nuevos datos.

Entonces, para hacer esto, querrías:

 return [content writeToFile:fullPath atomically:YES];