Oltre alla tecnica dei semafori trattata esaurientemente in altre risposte, ora possiamo usare XCTest in Xcode 6 per eseguire test asincroni tramite XCTestExpectation
. Ciò elimina la necessità di semafori durante il test del codice asincrono. Per esempio:
- (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];
}
Per il bene dei futuri lettori, mentre la tecnica del semaforo di invio è una tecnica meravigliosa quando assolutamente necessaria, devo confessare che vedo troppi nuovi sviluppatori, che non hanno familiarità con buoni schemi di programmazione asincrona, gravitano troppo rapidamente verso i semafori come meccanismo generale per rendere asincroni le routine si comportano in modo sincrono. Peggio ancora, ho visto molti di loro usare questa tecnica di semaforo dalla coda principale (e non dovremmo mai bloccare la coda principale nelle app di produzione).
So che questo non è il caso qui (quando è stata pubblicata questa domanda, non esisteva uno strumento carino come XCTestExpectation
; inoltre, in queste suite di test, dobbiamo assicurarci che il test non finisca fino a quando non viene eseguita la chiamata asincrona). Questa è una di quelle rare situazioni in cui potrebbe essere necessaria la tecnica del semaforo per bloccare il thread principale.
Quindi, con le mie scuse all'autore di questa domanda originale, per la quale la tecnica del semaforo è valida, scrivo questo avvertimento a tutti quei nuovi sviluppatori che vedono questa tecnica del semaforo e considerano l'applicazione nel loro codice come un approccio generale per trattare con asincrono metodi: essere avvisato che nove volte su dieci, la tecnica del semaforo non lo èl'approccio migliore quando si incontrano operazioni asincrone. Invece, familiarizza con i modelli di blocco / chiusura di completamento, nonché i modelli e le notifiche del protocollo delegato. Questi sono spesso modi molto migliori di affrontare compiti asincroni, piuttosto che usare i semafori per farli comportare in modo sincrono. Di solito ci sono buoni motivi per cui le attività asincrone sono state progettate per comportarsi in modo asincrono, quindi utilizzare il modello asincrono giusto anziché cercare di farle comportare in modo sincrono.
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
conwhile (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; }