Envío una vez (dispatch_once) singleton se congela / bloquea en el objective c

Esta línea de código se llama en mi método awakeFromFetch ubicado dentro de un object gestionado personalizado que implementa NSManagedObject . Esta línea en particular está haciendo una llamada a mi class de gestor de networking singleton llamada shanetworkingManager .

 [self setSync:(![[WKNetworkManager shanetworkingManager] objectHasPendingRequests:self.objectID]) ]; 

El bloque dispatch_once se activará como se muestra a continuación. Tenga en count que se implementa de una buena manera como se muestra aquí :

introduzca la descripción de la imagen aquí

La llamada dispatch_once luego va a la vez.h y aquí se congela a la derecha en la línea resaltada:

dipatch_once más profundo

Aquí está el seguimiento de stack:

traza de pila

Todo esto sucede cuando se intenta cargar un file de queue de networking previamente guardado. La aplicación se cierra completamente para save, y luego se vuelve a iniciar y luego se produce el locking / locking.

Incluso intenté usar este código para resolver el problema como se sugiere aquí , y no funcionó. Pero cambiar esto probablemente no importaría de todos modos, ya que mi código original de dispatch_once ha estado funcionando bien durante mucho time. Es solo en este caso particular.

 if ([NSThread isMainThread]) { dispatch_once(&onceToken, ^{ stack = [[KACoreDataStack alloc] init];}); } else { dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_once(&onceToken, ^{ stack = [[KACoreDataStack alloc] init];}); }); } 

Hasta ahora, estas son mis fonts para solucionar este tipo de problema:

  • La ejecución del código se detiene al usar el código de initialization Singleton seguro para subprocesss.
  • http://cocoasamurai.blogspot.jp/2011/04/singletons-your-doing-them-wrong.html
  • http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial
  • ios singleton class bloquea mi aplicación
  • http://benalpert.com/2014/04/02/dispatch-once-initialization-on-the-main-thread.html
  • http://www.bignerdranch.com/blog/dispatch_once-upon-a-time/

¡Gracias por tu ayuda!

Maldito hijo, ese es un buen trabajo para preguntar.

El problema aquí es que las llamadas recursivas a dispatch_once se bloquearán. Si desea detalles exactos, puede encontrarlos con la fuente aquí . Entonces necesitas reescribir para evitar eso.

Mi opinión es que hay un paso en falso arquitectónico con lo que lleva a esta llamada -loadQueueFromDisk . Absolutamente no quiere estar haciendo nada que sea tan ilimitado en el time de ejecución como cuando se sale y se carga algo del disco dentro de un dispatch_once . Lo que quiere hacer es el mínimo absoluto para crear un singleton direccionable y volver a salir. Luego, déle un estado interno de "Inicialización" y envíe el material de carga del disco a una queue sin locking en alguna parte. De esta forma, todo lo que no dependa de las cosas cargadas desde el disco puede continuar, y todo lo que haga depende de lo que se cargue desde el disco puede agregarse a la queue en la que está cargando el disco, o revisar cada cientos de milisegundos para ver si todavía está en un estado "inicializado", o algo por el estilo.

Gracias a la ayuda de alexcurylo, poner en queue el trabajo loadFromDisk abordó el problema. Para que las personas no se confundan, sucede que con este código a continuación estoy haciendo queue en un trabajo que carga un array (que actúa como una queue guardada de requestes de usuario) del disco. Podría estar haciendo queue en cualquier trabajo, como cargar imágenes / etc. El código siguiente en mi class shanetworkingManager (donde se llama la carga del disco) funcionó, como se muestra aquí:

 -(void) loadQueueFromFileByQueueing { //Create a Queue /* Note that fileStrQueue should be added to the .h file as NSOperationQueue *fileStrQueue;*/ fileStrQueue = [[NSOperationQueue alloc] init]; //Create an operation which will invoke method loadQueueFromDisk NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadQueueFromDisk) object:nil]; //Add this operation to the queue [fileStrQueue addOperation:operation]; //Releasing the above operation as it is already retained by the queue. // [operation release]; // If you are using ARC, this won't be necessary }