В дополнение к семафорной технике, подробно рассмотренной в других ответах, теперь мы можем использовать XCTest в Xcode 6 для выполнения асинхронных тестов через XCTestExpectation
. Это устраняет необходимость в семафорах при тестировании асинхронного кода. Например:
- (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];
}
Ради будущих читателей, хотя техника семафоров рассылки является замечательной техникой, когда она абсолютно необходима, я должен признаться, что вижу слишком много новых разработчиков, незнакомых с хорошими шаблонами асинхронного программирования, слишком быстро тяготеющих к семафорам в качестве общего механизма создания асинхронных процедуры ведут себя синхронно. Хуже того, я видел, что многие из них используют эту технику семафоров из основной очереди (и мы никогда не должны блокировать основную очередь в производственных приложениях).
Я знаю, что это не тот случай (когда этот вопрос был опубликован, не было такого хорошего инструмента, как XCTestExpectation
; также в этих тестах мы должны убедиться, что тест не завершится, пока не будет выполнен асинхронный вызов). Это одна из тех редких ситуаций, когда может понадобиться техника семафора для блокировки основного потока.
Поэтому, приношу свои извинения автору этого оригинального вопроса, для которого техника семафора является разумной, я пишу это предупреждение всем тем новым разработчикам, которые видят эту технику семафора и рассматривают ее применение в своем коде как общий подход к работе с асинхронными методы: имейте в виду, что в девяти случаях из десяти техника семафоров нелучший подход при включении асинхронных операций. Вместо этого ознакомьтесь с шаблонами завершения / закрытия, а также с шаблонами протоколов делегирования и уведомлениями. Часто это гораздо лучшие способы решения асинхронных задач, чем использование семафоров для синхронного поведения. Обычно есть веские причины, по которым асинхронные задачи были разработаны для асинхронного поведения, поэтому используйте правильный асинхронный шаблон, а не пытайтесь заставить их вести себя синхронно.
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
сwhile (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; }