如何正确地为用户提供网络反馈?

时间:2012-09-21 13:13:36

标签: iphone ios cocoa-touch networking nsurlconnection

我的应用程序使用后台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连接但互联网停滞时发生了什么。

4 个答案:

答案 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);
}