我的应用程序使用后台GCD队列中的同步NSURLConnection从Web服务检索货币汇率,如下所示:
// This method is called in background queue
- (NSData*)fetchDataWithURLStr:(NSString*)urlStr {
NSData *jsonData = nil;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
NSURL *url = [NSURL URLWithString:urlStr];
NSURLResponse *response = nil;
NSError *error = nil;
NSURLRequest *request = [NSURLRequest requestWithURL:url];
jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error != nil) {
NSString *errorMsg = nil;
NSInteger ec = [error code];
if (ec == NSURLErrorTimedOut || ec == NSURLErrorCannotConnectToHost) {
errorMsg = @"Data temporarily not available.";
}
// Call on main thread
dispatch_async(dispatch_get_main_queue(), ^{
// Present the error
[self showErrorWithCode:ec title:@"ERROR" message:errorMsg];
});
jsonData = nil;
}
return jsonData;
}
但问题通常是应用尝试获取数据,下载似乎永远在运行,没有任何反应。没有任何状态更新。通常我的WiFi只是停滞不前,我必须去设置,禁用并重新启用它。或者家里的WiFi路由器的互联网连接已关闭,但设备已连接到WiFi。
我真正想做的是提供有关网络目前究竟发生了什么的准确反馈。例如
“正在尝试联系服务器......” “等等......还在努力......” “你的互联网似乎破了......” “再试一次......” “收到回复......” “下载20%” “下载40%” “完成!”
关于正在发生的事情的确切反馈。
有人推荐MKNetworkKit,但感觉已经死了,没有任何反馈。
这个问题的解决方案适用于iOS吗?
编辑:我有可达性,但它没有给我这种我希望在网络中显示的反馈。此外,Reachability并没有告诉我当有WiFi连接但互联网停滞时发生了什么。
答案 0 :(得分:3)
这里的根本问题是,根据您的应用程序可用的信息,不可能(是不可能)对网络问题进行可靠的诊断。可能的原因太多了,如果不了解实际网络和/或访问其他诊断信息来源,其中一些原因根本无法区分。
答案 1 :(得分:0)
U可以使用Reachability类。
Here是一个使用此可访问性类的示例代码,并通知我们正在使用哪种类型的连接。示例代码来自apple。
看看&以同样的方式实施。
为了向用户显示进度,我建议使用其委托方法中的NSURLConnection
,您可以轻松获取连接/请求的状态。
在其中一个委托中,它给出了错误描述。
答案 2 :(得分:0)
您应该使用异步 API。在单独的工作线程/队列中使用同步API通常不是正确的方法(参见WWDC'12关于这些主题的视频)
更好的解决方案是使用较新的NSURLConnection
API和+sendAsynchronousRequest:queue:completionHandler:
方法,而不是使用sendSynchronousRequest: returningResponse: error:
。通过这种方式,您可以避免阻止API并在请求失败时被通知(无论是启动失败还是因运行而失败,因为网络中断等)。
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse*, NSData*, NSError*) {
// Code that will be executed asynchronously
// when the response to the request has been received
}];
// After the call to this method above, the code will continue executing
// WITHOUT WAITING for the network request to have its response.
这样您的用户界面就不会“冻结”,其余代码将继续运行,因此您可以在视图中显示一些进度指示器,例如,依此类推。只有在响应到达后,completionHandler
块中的代码才会异步调用(独立于代码的其余部分)。
此外,为了在网络本身无法访问(关闭等)时被通知,请使用Reachability [编辑]您似乎已经按照在问题的编辑中添加的那样执行此操作,因此您应该已经被告知关于这一点,并能够在这种情况下通知用户)
提示:您也可以使用一些第三方框架,例如优秀的[AFNetworking
(https://github.com/AFNetworking/AFNetworking),它允许您在发送网络请求时执行更多操作,例如在网络请求正在进行时调用Objective-C代码块,让您轻松了解下载的进度。
将AFNetworking
项目集成到工作区后,您就可以执行以下操作:
AFHTTPRequestOperation* reqOp = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
[reqOp setCompletionBlockWithSuccess: ^(AFHTTPRequestOperation *operation, id responseObject)
{
// Code to execute asynchronously when you successfully received the whole page/file requested
// The received data is accessible in the responseObject variable.
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Code to execute asynchronously when you request failed, for example if you have a network error, or received some 404 error code, etc.
progressLabel.text = [NSString stringWithFormat:@"Download error: %@", error];
}];
[reqOp setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead)
{
// Code to execute periodically each time a partial chunk of data is received
// So that you can update your progression. For example:
progressLabel.text = [NSString stringWithFormat:@"Downloading %.1f%%", (float)totalBytesRead*100.f/totalBytesExpectedToRead];
}];
[reqOp start]; // start the request
// The rest of the code will continue to execute, and the blocks mentioned above will be called asynchronously when necessary.
答案 3 :(得分:-1)
以下是我检查互联网连接的方法。您需要先添加可达性。
+ (BOOL) checkNetworkStatus
{
Reachability *reachability = [Reachability reachabilityForInternetConnection];
NetworkStatus networkStatus = [reachability currentReachabilityStatus];
return !(networkStatus == NotReachable);
}