0

我的应用程序使用后台 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 的此问题的解决方案?

编辑:我有可达性,但它没有给我这种我想在联网期间显示的反馈。此外,当有 WiFi 连接但互联网停止时,可达性并没有告诉我发生了什么。

4

4 回答 4

3

这里的基本问题是不可能(是不可能的)根据您的应用程序可用的信息对网络问题进行可靠的诊断。可能的原因太多了,如果不了解实际网络和/或访问其他诊断信息源,其中一些根本无法区分。

于 2012-09-22T04:24:42.577 回答
0

你可以使用可达性类。

是使用此可达性类的示例代码,并通知我们正在使用哪种类型的连接。示例代码来自苹果。

以相同的方式查看和实施。

为了向用户显示进度,我建议使用NSURLConnection其委托方法,您可以轻松获取连接/请求的状态。

在其委托之一中,它给出了错误描述。

于 2012-09-21T13:21:54.773 回答
0

您应该改用异步API。在单独的工作线程/队列中使用同步 API 通常不是正确的方法(请参阅有关这些主题的 WWDC'12 视频)

更好的解决方案是使用较新的NSURLConnectionAPI 和+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.

这样,您的 UI 不会“冻结”,其余代码将继续运行,因此您可以在视图上显示一些进度指示器,等等。仅当响应到达时,块中的代码completionHandler才会被异步调用(独立于您的其余代码)。

此外,要在网络本身无法访问(出现故障等)时得到通知,请对该 [EDIT] 使用 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.
于 2012-09-21T13:24:31.537 回答
-1

这是我检查互联网连接的方法。您需要先添加可达性。

+ (BOOL) checkNetworkStatus
{
   Reachability *reachability = [Reachability reachabilityForInternetConnection];
   NetworkStatus networkStatus = [reachability currentReachabilityStatus];
   return !(networkStatus == NotReachable);
}
于 2012-09-21T13:24:24.533 回答