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

时间:2009-05-25 23:27:19

标签: iphone objective-c uiwebview

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

10 个答案:

答案 0 :(得分:60)

我猜iframe会导致webViewDidStartLoad / webViewDidFinishLoad对。

作为答案提到的[webView isLoading]检查对我不起作用;即使在两次false次呼叫中的第一次呼叫后,它也会返回webViewDidFinishLoad。相反,我按如下方式跟踪加载:

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


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

  if (webViewLoads_ > 0) {
    return;
  }

  …
}

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

(注意这只有在开始/结束对不是连续出现的情况下才有效,但根据我的经验到目前为止还没有发生过。)

答案 1 :(得分:19)

检查一下,它肯定适合你:

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

答案 2 :(得分:9)

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

更新

请使用下面的phopkins答案代替我的!在您的应用程序中使用私有API是一个坏主意,您可能会被拒绝,他的解决方案是正确的。

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

你也可以使用我编写的这个简短的类别,它将块添加到UIWebView中,并且还允许您在默认UIWebView行为(在每个对象加载后得到通知)或“预期”行为之间进行选择(仅在页面完全通知时获得通知)加载)。

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

答案 5 :(得分:1)

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

这对我有用:

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

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

    //page loaded
}

答案 6 :(得分:1)

所有选项都不适用于我的用例。我用phopkins的例子略加修改。我发现,如果加载到webview中的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--;
}

答案 7 :(得分:0)

嗨,它可能已经有点远,但我希望这会有所帮助。

我只是在进入webViewDidFinishLoad方法时使用了通知,这样我就可以捕获该方法的一个实例,然后我将检测通知并从那里开始我的逻辑。

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

** * ** * *** 修改 * ** * ** * **

我做了一个测试并设法测试了它。它实际上是有效的,并且在加载完整页面后将调用从通知中调用的方法。

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

鼓励反馈。谢谢!

答案 8 :(得分:0)

这是我在DOM加载时用来显示微调器的内容,建立在@Vinod的答案之上。

请注意,webViewDidStartLoadwebViewDidFinishLoad之间 readyState 已完成来自之前的请求(如果有),这就是为什么轮询应该在webViewDidFinishLoad之后开始。

readyState 可能的值是加载交互式已完成(也许 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];
}

答案 9 :(得分:-6)

我这样做是这样的:

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