UIWebView – 如何识别“最后”的webViewDidFinishLoad消息?

webViewDidFinishLoad消息似乎每次加载页面中的任何对象时发送。 有没有办法确定所有的内容加载完成?

有趣的是,我不会想到它会这样工作。 虽然我确定还有其他方法可以做到这一点(有没有办法从webViewDidFinishLoad消息中提取URL,以便您可以看到哪一个是主页完成加载?),我能想到的主要事情是使用估计进度将检查页面的进度,并在100%完成加载时发生任何您想要执行的操作,这就是我在我的应用程序中执行的操作。 Google“iphone webview estimatedprogress”,点击第一个链接,我写了一个关于如何做这个的指南。

更新:

请使用phopkins的答案而不是我的! 在您的应用中使用私有API是一个坏主意,您可能会被拒绝,他的解决scheme是正确的。

我猜iframes导致webViewDidStartLoad / webViewDidFinishLoad对。

提到的[webView isLoading]检查并不适合我; 它甚至在两个webViewDidFinishLoad调用的第一个之后返回false 。 相反,我跟踪加载如下:

 - (void)webViewDidStartLoad:(UIWebView *)webView { webViewLoads_++; } - (void)webViewDidFinishLoad:(UIWebView *)webView { webViewLoads_--; if (webViewLoads_ > 0) { return; } … } - (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error { webViewLoads_--; } 

(注意这只有在开始/完成对没有连续出现的情况下才有效,但是到目前为止还没有发生。

检查这一个,它一定会为你工作:

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

用较less的控制监视加载进度的另一种方法是观察WebViewProgressEstimateChangedNotification,WebViewProgressFinishedNotification和WebViewProgressStartedNotification通知。 例如,您可以观察这些通知,在应用程序中实现一个简单的进度指示器。 通过调用estimatedProgress方法来更新进度指示器,以获取当前加载的内容数量的估计值。

来自http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/WebKit/Classes/WebView_Class/Reference/Reference.html

你也可以使用这个简短的我写的类添加到UIWebView的块,也可以让你select默认的UIWebView行为(每个对象加载后得到通知),或“预期”的行为(只有当页面完全加载时得到通知)。

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

所有的选项都不适合我的用例。 我用phopkins例子稍作修改。 我发现,如果加载到webview的HTML包含一个图像,这将是一个单独的请求发生连续,所以我们必须考虑到这一点,我用一个计时器。 不是最好的解决scheme,但它似乎工作:

 - (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--; } 

嗨,它可能已经有点远了,但我希望这有助于。

我刚刚使用通知,当它进入webViewDidFinishLoad方法,以便我可以捕获该方法的一个实例,然后我会检测通知,并从那里做我的逻辑。

希望这可以帮助。 它不会捕获webViewDidFinishLoad方法的最后一个被调用的实例,但允许您在调用该方法后执行某些操作,而不是重复调用该方法(例如显示button)。

** * ** * *** 编辑 * ** * ** * **

我做了一个testing,并设法testing出来。 它实际上工作,通知中调用的方法将在完整页面加载后调用。

或者,我想你可以在委托方法webViewDidStartLoad和webViewDidFinishLoad上做一个计数器,以确保它们在运行代码之前是相同的。 这是一个丑陋的黑客,因为我们永远不会知道它将被调用多less次,除非像我一样,你正在加载一个HTML源,并可以添加一个JavaScript来检查页面上有多less元素,你正在加载。 我只是分享一些我试图解决这个问题的方法。 希望它有帮助。

反馈是鼓励。 谢谢!

我需要从尚未完全加载的页面捕获variables。

这对我工作:

 - (void) webViewDidFinishLoad:(UIWebView *)webView { NSString *valueID = [webView stringByEvaluatingJavaScriptFromString:@"document.valueID;"]; if([valueID isEqualToString:@""]){ [webView reload]; return; } //page loaded } 

下面是我用来展示一个微调,而DOM加载,build立在@维诺德的答案的顶部。

请注意,在webViewDidStartLoadwebViewDidFinishLoad之间, readyState是从前一个请求(如果有)完成的,这就是轮询应该在webViewDidFinishLoad之后开始的webViewDidFinishLoad

readyState可能的值是加载交互完成 (也许没有 ?)

 - (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]; } 

我这样做的方式是:

 - (void)webViewDidFinishLoad:(UIWebView *)webview { if (webview.loading) return; // now really done loading code goes next [logic] }