除了其他答案中详细介绍的信号量技术外,我们现在可以在Xcode 6中使用XCTest通过 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");
[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]]; }
。 - nicktmro