web-dev-qa-db-ja.com

UIWebView-「最後の」webViewDidFinishLoadメッセージを識別する方法は?

WebViewDidFinishLoadメッセージが毎回送信されるようです どれか ページ内のオブジェクトが読み込まれました。コンテンツのすべての読み込みが完了したことを確認する方法はありますか?

22
chendral

興味深いことに、私はそれがそのように機能するとは思っていなかったでしょう。それを行う方法は他にもあると思いますが(webViewDidFinishLoadメッセージからURLを抽出して、ロードが完了したメインページがどれであるかを確認する方法はありますか?)、私が考えることができる主なことは、 EstimatedProgressは、ページの進行状況を確認し、読み込みが100%完了したときに、実行したいことをすべて実行します。これは、私のアプリで行うことです。グーグル「iphonewebviewestimatedprogress」そしてこれを行う方法について私が書いたガイドの最初のリンクをクリックしてください。

更新:

私の代わりに以下のポプキンスの答えを使ってください!アプリでプライベートAPIを使用することは悪い考えであり、おそらく拒否されるでしょう。彼の解決策は正しいものです。

9
AriX

IframeがwebViewDidStartLoad/webViewDidFinishLoadペアを引き起こすと推測しています。

[webView isLoading]答えとして言及されたチェックは私にはうまくいきませんでした。 2回のfalse呼び出しの最初の呼び出しの後でも、webViewDidFinishLoadを返しました。代わりに、次のように読み込みを追跡します。

- (void)webViewDidStartLoad:(UIWebView *)webView {
  webViewLoads_++;
}


- (void)webViewDidFinishLoad:(UIWebView *)webView {
  webViewLoads_--;

  if (webViewLoads_ > 0) {
    return;
  }

  …
}

- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error {
  webViewLoads_--;
}

(これは、開始/終了ペアが連続して来ない場合にのみ機能することに注意してください。しかし、これまでの私の経験では、それは起こりませんでした。)

61
Fiona Hopkins

これをチェックしてください、それは間違いなくあなたのために働くでしょう:

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    if ([[webView stringByEvaluatingJavaScriptFromString:@"document.readyState"] isEqualToString:@"complete"]) {
        // UIWebView object has fully loaded.
    }
}
19
Vinod Singh

すべてのオプションが私のユースケースでは実際には機能しませんでした。少し変更したポプキンの例を使用しました。 WebビューにロードされたHTMLに、連続して発生する個別のリクエストとなる画像が含まれている場合は、それを考慮する必要があることがわかり、タイマーを使用してそれを行いました。最善の解決策ではありませんが、うまくいくようです。

- (void)webViewActuallyFinished {
     _webViewLoads--;

    if (_webViewLoads > 0) {
        return;
    }

    //Actually done loading

}

- (void)webViewDidStartLoad:(UIWebView *)webView {
    _webViewLoads++;
}


- (void)webViewDidFinishLoad:(UIWebView *)webView {


    [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(webViewActuallyFinished) userInfo:nil repeats:NO];
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
  _webViewLoads--;
}
1
David Corrado

まだ完全にロードされていないページから変数をキャプチャする必要がありました。

これは私のために働いた:

- (void) webViewDidFinishLoad:(UIWebView *)webView {
    NSString *valueID = [webView stringByEvaluatingJavaScriptFromString:@"document.valueID;"];

    if([valueID isEqualToString:@""]){
        [webView reload];
        return;
    }

    //page loaded
}
1
Petr

UIWebViewにブロックを追加し、デフォルトのUIWebView動作(各オブジェクトのロード後に通知を受け取る)または「予期される」動作(ページが完全にロードされたときにのみ通知を受け取る)のいずれかを選択できる、私が書いたこの短いカテゴリを使用することもできます。

https://github.com/freak4pc/UIWebView-Blocks

1
Shai Mishali

より少ない制御でロードの進行状況を監視する別の方法は、WebViewProgressEstimateChangedNotification、WebViewProgressFinishedNotification、およびWebViewProgressStartedNotification通知を監視することです。たとえば、これらの通知を監視して、アプリケーションに単純な進行状況インジケーターを実装できます。 estimatedProgressメソッドを呼び出して進行状況インジケーターを更新し、現在読み込まれているコンテンツの量の見積もりを取得します。

から http://developer.Apple.com/library/mac/#documentation/Cocoa/Reference/WebKit/Classes/WebView_Class/Reference/Reference.html

1
KarenAnne

これは、@ Vinodの回答に基づいて構築された、DOMの読み込み中にスピナーを表示するために使用するものです。

webViewDidStartLoadwebViewDidFinishLoadの間のreadyStateは、前のリクエストからの完了であることに注意してください(存在する場合)、そのため、ポーリングはwebViewDidFinishLoadの後に開始する必要があります。

readyState可能な値はloadinginteractiveまたはcompleted(そして多分nil?)

- (void)webViewDidStartLoad:(UIWebView *)webView {
    [self spinnerOn];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    [self startDOMCompletionPolling];
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
    [self startDOMCompletionPolling];
}


- (void)startDOMCompletionPolling {
    if (self.domCompletionListener) {
        [self.domCompletionListener invalidate];
    }
    self.domCompletionListener = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(checkDOMCompletion) userInfo:nil repeats:YES];
}

- (void)checkDOMCompletion {
    NSString *readyState = [self.webView stringByEvaluatingJavaScriptFromString:@"document.readyState"];

    if (readyState != nil) {
        if (readyState.length > 0) {
            if ([readyState isEqualToString:@"loading"]) { //keep polling
                return;
            }
        }
    }
    //'completed', 'interactive', nil, others -> hide spinner
    [self.domCompletionListener invalidate];
    [self spinnerOff];
}
0
codrut

こんにちは、もう少し遠いかもしれませんが、これがお役に立てば幸いです。

webViewDidFinishLoadメソッドに入るときに通知を使用したので、メソッドのインスタンスを1つキャプチャして、通知を検出し、そこからロジックを実行します。

お役に立てれば。 webViewDidFinishLoadメソッドの最後に呼び出されたインスタンスをキャプチャしませんが、一度呼び出されると、その特定のメソッドへの繰り返しの呼び出し(ボタンの表示など)を行わないようにすることができます。

**​​*******[〜#〜]編集[〜#〜]********* ==

私はテストを行い、なんとかそれをテストすることができました。実際に機能し、通知から呼び出されたメソッドは、ページ全体が読み込まれた後に呼び出されます。

または、デリゲートメソッドwebViewDidStartLoadとwebViewDidFinishLoadでカウンターを実行して、コードを実行する前にそれらが同じであることを確認できると思います。ただし、これは醜いハックです。私のように、HTMLフィードを読み込んでいて、JavaScriptを追加して、読み込んでいるページに要素がいくつあるかを確認しない限り、何回呼び出されるかはわかりません。私はこれを解決しようとしたいくつかの方法を共有しています。それが役に立てば幸い。

フィードバックをお勧めします。ありがとう!

0
faterpig