UIWebView的进度条(和networking活动状态)

经过长时间的rest,我又开始做ios开发了。 考虑到这一点,我下载了最新版本的XCode(5.02),并设置了以ios7作为目标的应用程序编码。 一切都很好,直到我添加一个“webView页面”到我的应用程序。 我天真地期待UIWebView像Safari中的页面一样工作,但事实并非如此。 最明显的缺点是在加载页面时,用户完全没有反馈。 即networking活动指示器完全不显示,页面加载时不显示进度条。 所以我想你只需要手动添加这些。 那不应该太难,应该吗?

几天后,我得到了很好的工作,但我不满意的结果。 我花了很多的debugging和试验来获得我现在的位置。 我想我的问题是“有什么可以改进我的方法吗?” 也可能是“我应该向苹果公司报告装载和请求财产问题,并要求他们解决这些问题”?

最初,我在网上寻找解决这个问题的方法,关于它的stackoverflow有几个问题,但似乎没有人真正破解它。 一些build议的方法:

  1. 使用一个私人的UIWebView API(如果你想把你的应用程序发布到商店就不好)
  2. 使用NSURLConnection下载页面(仅提供初始页面下载的进度)
  3. 使用第三方库下载和处理页面(大锤破解螺母?)
  4. 使用一个UIWebViewDelegate并保持加载开始和结束的轨迹
  5. 使用UIWebViewDelegate手动显示和隐藏networking活动指示器

最后我决定使用4.和5.但是它很棘手,因为:

  1. 开始和结束通话可以按任何顺序进行
  2. 一些请求开始,但从未完成
  3. 一些请求完成时出现错误

第一个问题可以通过计算启动和结束来解决,通过确保计算的进度百分比仅仅增加,并且在最后一个请求完成时只closuresnetworking指示器。

第二个问题更难解决。 UIWebView有两个属性,原则上可以用来做(加载和请求),但他们似乎以神秘的方式工作。 我在这里find的一些答案和评论build议,加载属性从来没有更新,但要求是。 这对我来说最初是有道理的,因为页面从来没有真正停止加载(他们可能有dynamic内容),所以加载属性只会告诉你,如果Web视图正在积极加载内容(即如果loadRequest已被调用,stopLoading hasn “T)。

但是,至less在ios7上,它实际上是以相反的方式工作的。 请求属性永远不会更新,所以你不能使用请求属性来确定视图是否已经完成加载一切(即通过检查已完成的请求是否是初始请求)。 加载属性会更新,当页面完全加载时,它会被设置为NO。 这有很大的帮助,但我注意到,dynamic内容(例如页面广告)导致加载重置为YES,所以处理仍然有点棘手。

第三个问题不会是一个问题,除非我已经观察到,在webView:didFailLoadWithError中加载属性始终设置为NO。 这似乎是一个临时的状态,但是,如果你想你可以忽略错误,并等待加载被设置为NO在webViewDidFinishLoad。 由于请求属性没有更新,所以不可能知道它是最初的失败请求还是其中一个子请求(你可能会也可能不关心)。 所以我决定采用一种解决scheme,让程序员select他们想要的行为。

事情会更容易,如果:

  1. 请求属性已更新(或当前请求已传入,就像在webView中:shouldStartLoadWithRequest:navigationType)
  2. 在webView:didFailLoadWithError中加载属性设置正确

这里是我的代码在视图控制器的webView:

- (void)resetProgress { framesToLoad = 0; framesLoaded = 0; currentProgress = 0.0f; } - (void)resetForNewPage { // Reset progress [self resetProgress]; // Monitor the page load monitorProgress = YES; // Keep going if errors occur // completeIfError = NO; // Stop updates if an error occurs completeIfError = YES; } - (void)webViewLoaded { [self resetProgress]; [entryProgressView setProgress: 0.0f animated: YES]; } - (void)viewDidLoad { [super viewDidLoad]; // Reset state for new page load [self resetForNewPage]; // Load the page NSURLRequest *entryRequest = [NSURLRequest requestWithURL:entryURL]; [entryWebView loadRequest:entryRequest]; } -(void)viewWillDisappear:(BOOL)animated { [entryWebView stopLoading]; entryWebView.delegate = nil; [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; } - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if (navigationType == UIWebViewNavigationTypeLinkClicked) { // Reset state for new page load [self resetForNewPage]; } return YES; } -(void)webViewDidStartLoad:(UIWebView *)webView { [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; if (!monitorProgress) { return; } // Increment frames to load counter framesToLoad++; } -(void)webViewDidFinishLoad:(UIWebView *) webView { if (!monitorProgress) { [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; return; } // Increment frames loaded counter framesLoaded++; // Update progress display float newProgress = ((float) framesLoaded) / framesToLoad; if (newProgress > currentProgress) { currentProgress = newProgress; [entryProgressView setProgress: newProgress animated: YES]; } // Finish progress updates if loading is complete if (!webView.loading) { [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; monitorProgress = NO; [entryProgressView setProgress: 1.0 animated: YES]; [self performSelector:@selector(webViewLoaded) withObject: nil afterDelay: 1.0]; } } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { if (!monitorProgress) { [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; return; } // Increment frames loaded counter framesLoaded++; // Update progress display float newProgress = ((float) framesLoaded) / framesToLoad; if (newProgress > currentProgress) { currentProgress = newProgress; [entryProgressView setProgress: newProgress animated: YES]; } // Finish progress updates if required if (completeIfError) { [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; monitorProgress = NO; [entryProgressView setProgress: 1.0 animated: YES]; [self performSelector:@selector(webViewLoaded) withObject: nil afterDelay: 1.0]; } }