Além da técnica do semáforo abordada exaustivamente em outras respostas, agora podemos usar o XCTest no Xcode 6 para executar testes assíncronos via XCTestExpectation
. Isso elimina a necessidade de semáforos ao testar código assíncrono. Por exemplo:
- (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];
}
Para o bem dos futuros leitores, embora a técnica de semáforo de expedição seja uma técnica maravilhosa quando absolutamente necessária, devo confessar que vejo muitos desenvolvedores novos, não familiarizados com bons padrões de programação assíncronos, gravitando muito rapidamente em semáforos como um mecanismo geral para tornar assíncrona rotinas se comportam de forma síncrona. Pior, já vi muitos deles usarem essa técnica de semáforo na fila principal (e nunca devemos bloquear a fila principal nos aplicativos de produção).
Sei que esse não é o caso aqui (quando esta pergunta foi publicada, não havia uma ferramenta interessante como XCTestExpectation
; também, nesses conjuntos de testes, devemos garantir que o teste não termine até que a chamada assíncrona seja concluída). Essa é uma daquelas situações raras em que a técnica de semáforo para bloquear o encadeamento principal pode ser necessária.
Portanto, com minhas desculpas ao autor desta pergunta original, para quem a técnica de semáforo é sólida, escrevo este aviso a todos os novos desenvolvedores que veem essa técnica de semáforo e considero aplicá-la em seu código como uma abordagem geral para lidar com assinaturas assíncronas. métodos: esteja avisado que nove em cada dez vezes, a técnica do semáforo não éa melhor abordagem ao contar operações assíncronas. Em vez disso, familiarize-se com os padrões de bloqueio / fechamento de conclusão, bem como com padrões e notificações de protocolo de delegação. Geralmente, essas são maneiras muito melhores de lidar com tarefas assíncronas, em vez de usar semáforos para fazê-las se comportar de maneira síncrona. Geralmente, existem boas razões para as tarefas assíncronas terem sido projetadas para se comportarem de maneira assíncrona, portanto, use o padrão assíncrono correto, em vez de tentar fazê-las se comportar de maneira síncrona.
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
comwhile (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; }