我的假设是operation
在一个单独的线程上异步运行,但循环永远不会退出,所以某些东西不是我想象的那样。
/**
Checks if we can communicate with the APIs
@result YES if the network is available and all of the registered APIs are responsive
*/
- (BOOL)apisAvailable
{
// Check network reachability
if (!_connectionAvailable) {
return NO;
}
// Check API server response
NSMutableSet *activeOperations = [[NSMutableSet alloc] init];
__block NSInteger successfulRequests = 0;
__block NSInteger failedRequests = 0;
for (AFHTTPClient *httpClient in _httpClients) {
// Send heart beat request
NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:@"" parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// Server returned good response
successfulRequests += 1;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Server returned bad response
failedRequests += 1;
}];
[operation start];
[activeOperations addObject:operation];
}
// Wait for heart beat requests to finish
while (_httpClients.count > (successfulRequests + failedRequests)) {
// Wait for each operation to finish, one at a time
//usleep(150);
[NSThread sleepForTimeInterval:0.150];
}
// Check final results
if (failedRequests > 0) {
return NO;
}
return YES;
}
答案 0 :(得分:2)
一些建议:
永远不要检查可达性以确定请求是否成功。你应该试试这个请求;只有当它失败时你才应该咨询可达性,以便尽可能地得到最好的猜测。可达性使 no 保证请求是否会失败或成功。
是否在主线程上调用此方法?即使您使用永不完成的请求修复了问题,它也会在网络请求运行的整个过程中阻止UI。由于这些请求可能需要很长时间,因此对于用户来说这是一种糟糕的体验,如果操作系统在错误的时间(例如在发布时)发生,操作系统将会终止您的应用。
在调用sleep或者等效的时候循环会浪费CPU资源和内存,并且会阻止线程的runloop为任何定时器,事件处理程序或回调提供服务。 (这可能是网络完成块永远无法运行的原因。)如果你可以避免阻塞线程,你应该这样做。另外,如果你在自己没有创造的NSThread上做这件事,Cocoa往往会感到不快。
我看到两个选项:
使用dispatch_group
等待所有请求完成。而不是阻止你的调用线程,你应该在完成时使用完成块来调用。因此,不是返回BOOL,而是选择一个带有BOOL的完成块。像- (void)determineIfAPIIsAvailable:(void(^)(BOOL))completionBlock;
完全摆脱这种方法。你用这种方法做什么的?当事情失败时,尝试使用您的API并向用户报告适当的错误几乎肯定是一个更好的主意,而不是试图猜测API的请求是否会事先成功。
答案 1 :(得分:0)
我认为问题在于我没有使用锁定来递增计数器,因此while循环永远不会计算为true
。
只要它被任何请求回调块递增,然后我就知道该做什么,我只能通过查找大于0
的失败计数来使其工作。
我恰好已经切换到[NSOperationQueue waitUntilAllOperationsAreFinished]
。
最终代码:
/**
Checks if we can communicate with the APIs
@result YES if the network is available and all of the registered APIs are responsive
*/
- (BOOL)apisAvailable
{
// Check network reachability
if (!_connectionAvailable) {
return NO;
}
// Check API server response
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
__block NSInteger failedRequests = 0;
for (AFHTTPClient *httpClient in _httpClients) {
// Send heart beat request
NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:@"" parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// Server returned good response
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Server returned bad response
failedRequests += 1;
}];
[operationQueue addOperation:operation];
}
// Wait for heart beat requests to finish
[operationQueue waitUntilAllOperationsAreFinished];
// Check final results
if (failedRequests > 0) {
return NO;
}
return YES;
}