Actualmente estoy trabajando en una aplicación de iPhone y tengo una biblioteca de un tercero que tiene un comportamiento asíncrono, pero me gustaría envolverla con mi propia clase y hacer que parezca sincrónica.¿Cómo ajustar una clase asíncrona para que sea sincrónica? Use NSRunLoop?
La clase central en esta biblioteca, llamémosla clase de conexión, tiene varias funciones que tienen su resultado final resuelto cuando se llaman los métodos en una instancia de una clase de delegado. Lo que trato de hacer es ajustar esta clase y delegar para que parezca ser sincrónica en lugar de asincrónica. Si estuviera haciendo esto en Java, usaría FutureTask o CountdownLatch o simplemente join(). Pero no estoy seguro de la mejor manera de hacerlo en Objective C.
Comencé creando una extensión NSThread, NFCThread, que se ajusta al protocolo delegado mencionado anteriormente. La idea es que inicie y NFCThread, pase la instancia de NFCThread al método setDelegate de Connection, inicie el hilo y luego llame a un método asincrónico en Connection. Mi expectativa es que uno de los tres métodos de delegado en la instancia de NFCThread se llamaría finalmente haciendo que el hilo salga.
Para simular una unión, hice lo siguiente. He añadido una NSConditionalLock a NFCThread:
joinLock = [[NSConditionLock alloc] initWithCondition:NO];
El código alrededor de la llamada a la conexión se ve algo como esto:
NFCThread *t = [[NFCThread alloc] init];
[connection setDelegate:t];
[t start];
[connection openSession];
// Process errors, etc...
[t.joinLock lockWhenCondition:YES];
[t.joinLock unlock];
[t release];
[connection setDelegate:nil];
El protocolo para el delegado tiene tres métodos. En NFCThread he implementado cada método algo como esto:
- (void)didReceiveMessage:(CommandType)cmdType
data:(NSString *)responseData
length:(NSInteger)length {
NSLog(@"didReceiveMessage");
// Do something with data and cmdType...
[joinLock lock];
[joinLock unlockWithCondition:YES];
callBackInvoked = YES;
}
sobrecargué principal método de NFCThread de modo que simplemente bucles continuamente. Algo como esto:
while (!callBackInvoked) { ; }
He descubierto que esto no es realmente una buena idea, ya que provocan uso de la CPU para ir a través del techo. Así que en lugar He intentado utilizar un bucle de ejecución de algunos ejemplos que encontré en este sitio:
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (!callBackInvoked) {
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
En mis dos implementaciones, el hilo principal siempre está bloqueada y parece que ninguno de los métodos de delegado se llamó nunca. Sin embargo, sé que la biblioteca funciona correctamente y que las llamadas a los métodos de delegado normalmente se llaman.
Siento que me falta algo obvio aquí. Cualquier ayuda muy apreciada.
Rich
Gracias, Firoze. Sí, nuestra intención es tener nuestra llamada síncrona para bloquear. Esta biblioteca de terceros realmente está interactuando con una tarjeta SD, pero creo que es solo un detalle. Además, luego de una inspección más cercana, solo determiné que las llamadas a los métodos de delegado también ocurren en el hilo principal. ¿Podría esto hacer que toda esta discusión sea discutible? – richever
Bueno, no estoy seguro de que sea discutible. El problema es que si desea bloquear la llamada y bloquea el hilo principal, esta otra biblioteca no puede finalizar su trabajo. Entonces, una respuesta sería hacer la llamada síncrona desde un hilo diferente, que bloquearía * ese * hilo, pero aún permitiría que el hilo principal continuase funcionando normalmente. Por supuesto, si termina creando y bloqueando muchos hilos de esta manera, eso no es muy bueno. En cualquier caso, pensaría en * por qué * quieres esta sincronización y quizás pienses en una forma no bloqueante para hacer lo mismo (requiere saber más de lo que estás tratando de hacer aquí) –
Llamo al método de bloqueo en un hilo diferente ahora, como sugirió Firoze, y parece que funciona. Más o menos Ver mi pregunta de seguimiento: http://stackoverflow.com/questions/3444557/error-at-nsrunloop-después-return-from-thread-method-with-nsautoreleasepool – richever