Además de la técnica de semáforo cubierta exhaustivamente en otras respuestas, ahora podemos usar XCTest en Xcode 6 para realizar pruebas asincrónicas a través de XCTestExpectation
. Esto elimina la necesidad de semáforos al probar el código asincrónico. Por ejemplo:
- (void)testDataTask
{
XCTestExpectation *expectation = [self expectationWithDescription:@"asynchronous request"];
NSURL *url = [NSURL URLWithString:@"http://www.apple.com"];
NSURLSessionTask *task = [self.session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
XCTAssertNil(error, @"dataTaskWithURL error %@", error);
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = [(NSHTTPURLResponse *) response statusCode];
XCTAssertEqual(statusCode, 200, @"status code was not 200; was %d", statusCode);
}
XCTAssert(data, @"data nil");
// do additional tests on the contents of the `data` object here, if you want
// when all done, Fulfill the expectation
[expectation fulfill];
}];
[task resume];
[self waitForExpectationsWithTimeout:10.0 handler:nil];
}
Por el bien de los futuros lectores, si bien la técnica de despacho de semáforos es una técnica maravillosa cuando es absolutamente necesaria, debo confesar que veo demasiados desarrolladores nuevos, no familiarizados con buenos patrones de programación asincrónica, gravitan demasiado rápido a los semáforos como un mecanismo general para hacer asíncrono Las rutinas se comportan sincrónicamente. Peor aún, he visto a muchos de ellos usar esta técnica de semáforo desde la cola principal (y nunca debemos bloquear la cola principal en las aplicaciones de producción).
Sé que este no es el caso aquí (cuando se publicó esta pregunta, no había una buena herramienta como XCTestExpectation
; también, en estas suites de prueba, debemos asegurarnos de que la prueba no termine hasta que se realice la llamada asincrónica). Esta es una de esas situaciones raras en las que podría ser necesaria la técnica de semáforo para bloquear el hilo principal.
Entonces, con mis disculpas al autor de esta pregunta original, para quien la técnica del semáforo es sólida, escribo esta advertencia a todos los nuevos desarrolladores que ven esta técnica del semáforo y consideran aplicarla en su código como un enfoque general para tratar con asincrónico métodos: Tenga en cuenta que nueve de cada diez veces, la técnica del semáforo no esEl mejor enfoque al encontrar operaciones asincrónicas. En su lugar, familiarícese con los patrones de cierre / bloqueo de finalización, así como con los patrones y notificaciones de protocolo delegado. A menudo, estas son formas mucho mejores de tratar con tareas asincrónicas, en lugar de utilizar semáforos para que se comporten de forma sincrónica. Por lo general, hay buenas razones por las que las tareas asincrónicas se diseñaron para que se comporten de forma asincrónica, por lo que debe utilizar el patrón asincrónico correcto en lugar de intentar que se comporten de forma sincrónica.
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
conwhile (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; }