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に、接続/リクエストのステータスを簡単に取得できるデリゲート メソッドを使用することをお勧めします。

そのデリゲートの 1 つで、エラーの説明が表示されます。

于 2012-09-21T13:21:54.773 に答える
0

代わりに非同期APIを使用する必要があります。別のワーカー スレッド/キューで同期 API を使用することは、多くの場合、適切な方法ではありません (これらのテーマについては、WWDC'12 のビデオを参照してください)。

より良い解決策は、 を使用する代わりに、新しいNSURLConnectionAPI とメソッドを使用することです。こうすることで、API のブロックを回避し、リクエストが失敗したときに通知を受け取ることができます (開始に失敗したか、ネットワークがダウンしたために実行中に失敗したなど)。+sendAsynchronousRequest:queue:completionHandler:sendSynchronousRequest: returningResponse: error:

[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 を使用します。質問の EDIT で追加したように、すでにこれを行っているようです。この場合、ユーザーに通知することができます)


ヒント: 優れた [ 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 に答える