objective-c UIWebView - 如何识别“最后一个”webViewDidFinishLoad 消息?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/908367/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIWebView - How to identify the "last" webViewDidFinishLoad message?
提问by chendral
The webViewDidFinishLoad message seems to be sent each time anyobject in the page has been loaded. Is there a way to determine that all loading of content is done?
每次加载页面中的任何对象时,似乎都会发送 webViewDidFinishLoad 消息。有没有办法确定所有内容加载都已完成?
采纳答案by AriX
Interesting, I wouldn't have thought it would work like that. Although I'm sure there are other ways to do it (is there a way to extract the URL from the webViewDidFinishLoad message so that you can see which one is the main page finishing loading?), the main thing I can think of is using the estimatedProgress to check the progress of the page and fire off whatever you want to do when it's 100% finished loading, which is what I do in my app. Google "iphone webview estimatedprogress" and click the first link for a guide I wrote on how to do this.
有趣的是,我没想到它会这样工作。虽然我确定还有其他方法可以做到(有没有办法从 webViewDidFinishLoad 消息中提取 URL,以便您可以看到哪个是主页面完成加载?),但我能想到的主要是使用用于检查页面进度并在 100% 完成加载时触发您想做的任何事情的estimatedProgress,这就是我在我的应用程序中所做的。谷歌“iphone webview估计进度”并单击第一个链接以获取我编写的有关如何执行此操作的指南。
Update:
更新:
Please use phopkins' answer below instead of mine! Using private APIs in your apps is a bad idea and you will probably get rejected, and his solution is the right one.
请使用下面 phopkins 的答案而不是我的答案!在您的应用程序中使用私有 API 是一个坏主意,您可能会被拒绝,而他的解决方案是正确的。
回答by Fiona Hopkins
I'm guessing that iframes cause the webViewDidStartLoad/ webViewDidFinishLoadpair.
我猜 iframe 会导致webViewDidStartLoad/webViewDidFinishLoad对。
The [webView isLoading]check mentioned as an answer didn't work for me; it returned falseeven after the first of two webViewDidFinishLoadcalls. Instead, I keep track of the loading as follows:
[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_--;
}
(Note this will only work if the start / finished pairs don't come serially, but in my experience so far that hasn't happened.)
(请注意,这仅在开始/完成对不连续出现时才有效,但根据我的经验,到目前为止还没有发生。)
回答by Vinod Singh
Check this one, it will definitely work for you:
检查这个,它肯定对你有用:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if ([[webView stringByEvaluatingJavaScriptFromString:@"document.readyState"] isEqualToString:@"complete"]) {
// UIWebView object has fully loaded.
}
}
回答by KarenAnne
Another way to monitor load progress with less control is to observe the WebViewProgressEstimateChangedNotification, WebViewProgressFinishedNotification, and WebViewProgressStartedNotification notifications. For example, you could observe these notifications to implement a simple progress indicator in your application. You update the progress indicator by invoking the estimatedProgress method to get an estimate of the amount of content that is currently loaded.
另一种以较少控制监控加载进度的方法是观察 WebViewProgressEstimateChangedNotification、WebViewProgressFinishedNotification 和 WebViewProgressStartedNotification 通知。例如,您可以观察这些通知以在您的应用程序中实现一个简单的进度指示器。您可以通过调用estimatedProgress 方法来更新进度指示器,以获得当前加载的内容量的估计值。
回答by Shai Mishali
You can also use this short Category I wrote that adds blocks into UIWebView and also lets you choose between default UIWebView behavior (getting notified after each object load), or the "expected" behavior (getting notified only when the page has fully loaded).
您还可以使用我编写的这个简短的类别,将块添加到 UIWebView 中,还可以让您在默认 UIWebView 行为(在每个对象加载后收到通知)或“预期”行为(仅在页面完全加载时收到通知)之间进行选择。
回答by Petr
I needed to capture a variable from the page which was not fully loaded yet.
我需要从尚未完全加载的页面中捕获一个变量。
This worked for me:
这对我有用:
- (void) webViewDidFinishLoad:(UIWebView *)webView {
NSString *valueID = [webView stringByEvaluatingJavaScriptFromString:@"document.valueID;"];
if([valueID isEqualToString:@""]){
[webView reload];
return;
}
//page loaded
}
回答by David Corrado
All of the options did not really work for my use case. I used phopkins example slightly modified. I found that if the HTML loaded into the webview contained an image that would be a separate request that happened serially so we have to account for that and I did that with a timer. Not the best solution but it seems to work.:
所有选项都不适用于我的用例。我使用的 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--;
}
回答by faterpig
hi it may be a bit far back already but i hope this helps.
嗨,它可能已经有点远了,但我希望这会有所帮助。
i just used a notification when it enters the webViewDidFinishLoad method so that i can capture one instance of the method and then i'll detect the notification and do my logic from there.
我只是在它进入 webViewDidFinishLoad 方法时使用了一个通知,以便我可以捕获该方法的一个实例,然后我将检测该通知并从那里执行我的逻辑。
hope this helps. it does not capture the last called instance of the webViewDidFinishLoad method, but allows you to do something once it has been called and not be repeated calls to that particular method (eg. showing a button) too.
希望这可以帮助。它不会捕获 webViewDidFinishLoad 方法的最后一个调用实例,但允许您在调用它后执行某些操作,并且也不会重复调用该特定方法(例如,显示按钮)。
*********EDIT*********
** *** ****编辑*** *** ***
i did a test and managed to test it out. it actually works and the method called from the notification will be called after the full page has been loaded.
我做了一个测试并设法测试了它。它实际上有效,并且在加载完整页面后将调用从通知中调用的方法。
alternatively, i think you can do a counter on the delegate method webViewDidStartLoad and also on webViewDidFinishLoad to make sure that they are the same before you run your codes. this though, is an ugly hack as we will never know how many times it will be called unless like me, you are loading a html feed and can add a JavaScript to check how many elements there are on the page that you are loading. i'm just sharing some of the methods i have tried to solve this. hope it helps.
或者,我认为您可以在委托方法 webViewDidStartLoad 和 webViewDidFinishLoad 上做一个计数器,以确保在运行代码之前它们是相同的。尽管如此,这是一个丑陋的黑客,因为我们永远不会知道它会被调用多少次,除非像我一样,你正在加载一个 html 提要,并且可以添加一个 JavaScript 来检查你正在加载的页面上有多少元素。我只是分享一些我试图解决这个问题的方法。希望能帮助到你。
feedback is encouraged. thanks!
鼓励反馈。谢谢!
回答by codrut
Here's what I use to show a spinner while DOM loads, built on top of @Vinod's answer.
这是我用来在 DOM 加载时显示微调器的内容,建立在@Vinod 的回答之上。
Note that between webViewDidStartLoadand webViewDidFinishLoadthe readyStateis completedfrom the previous request (if any), that's why the polling should begin after webViewDidFinishLoad.
请注意,与webViewDidStartLoad和webViewDidFinishLoad该readyState的是完成从以前的请求(如果有的话),这就是为什么要投票后开始webViewDidFinishLoad。
readyStatepossible values are loading, interactiveor completed(and maybe nil?)
readyState可能的值是loading、interactive或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];
}
回答by KeithF
The way I do it is this:
我的做法是这样的:
- (void)webViewDidFinishLoad:(UIWebView *)webview {
if (webview.loading)
return;
// now really done loading code goes next
[logic]
}

