25

I have a simple iOS native app that loads a single UIWebView. I would like the webView to show an error message if the app doesn't COMPLETELY finish loading the initial page in the webView within 20 seconds.

I load my URL for the webView within my viewDidLoad like this (simplified):

[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.example.com"] cachePolicy:NSURLCacheStorageAllowed timeoutInterval:20.0]];

The timeoutInterval within the code above does not actually "do" anything, as Apple has it set within the OS to not actually time out for 240 seconds.

I have my webView didFailLoadWithError actions set, but if the user HAS a network connection, this never gets called. The webView just continues to try loading with my networkActivityIndicator spinning.

Is there a way to set a timeout for the webView?

4
  • 1
    somebody here said the timeout interval is for connection. Once it connected to server, it won't throw error anymore. You need to implement your own NSTimer after it connected in webViewDidStartLoad and cancel by yourself stackoverflow.com/questions/1883888/… Commented Jul 23, 2012 at 15:45
  • That looks like exactly what I'm looking for... could you maybe give me some guidance on how to implement it? (I'm an Objective-C newby) Commented Jul 23, 2012 at 15:48
  • I just need to know what to put for this: -(void)webView: NSTimer * theTimer { NSLog(@"Me is here at 1 minute delay"); } Like which target method would I use? Commented Jul 23, 2012 at 15:58
  • I just wrote a very basic code that you may want to start from :) hope it helps Commented Jul 23, 2012 at 16:03

4 Answers 4

41

The timeoutInterval is for connection. Once webview connected to the URL, you'll need to start NSTimer and do your own timeout handling. Something like:

// define NSTimer *timer; somewhere in your class

- (void)cancelWeb
{
    NSLog(@"didn't finish loading within 20 sec");
    // do anything error
}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    [timer invalidate];
}

- (void)webViewDidStartLoad:(UIWebView *)webView
{
    // webView connected
    timer = [NSTimer scheduledTimerWithTimeInterval:20.0 target:self selector:@selector(cancelWeb) userInfo:nil repeats:NO];
}
Sign up to request clarification or add additional context in comments.

32 Comments

I added the methods above, but it doesn't do anything after 20 seconds? - I put in a UIAlertView inside of the cancelWeb property but it never fires.
sorry one change, not NSTimer timerWithTimeInterval but scheduledTimerWithTimeInterval. Once your webView connected to the URL, webViewDidStartLoad will be invoked. If not, you didn't set delegate correctly. Then that method starts timer to call cancelWeb method in 20 seconds.
Thanks so much!!! Works perfectly :) One more question - do I need to do anything to release the timer if they exit the app in the viewWillDisappear or viewDidUnload?
you can just skip first webViewDidStartLoad by using some kind of flag variable. when user clicks a link in the first page, the webView will start and call webViewDidStartLoad again each time. You need to determine if it's first load or later loads by users' click. Or you can insert js to handle user's click, but maybe that's too much. I hope this answers to your question
oh I see. that sucks. you probably need to communicate b/w your code and js code on jquery-mobile. I would give a shot with stringByEvaluatingJavaScriptFromString:, or this might work stackoverflow.com/questions/5671742/… . I even consider phonegap or some kind of webView base framework maybe.. sorry I can't help that much
|
9

All of the suggested solutions are not ideal. The correct way to handle this is using the timeoutInterval on the NSMutableURLRequest itself:

NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://web.site"]];

request.timeoutInterval = 10;

[webview loadRequest:request];

2 Comments

Will this call didFailToLoad withError after timeout?
@AlbertRenshaw yes, it calls the delegate method automatically
3

My way is similar to accepted answer but just stopLoading when time out and control in didFailLoadWithError.

- (void)timeout{
    if ([self.webView isLoading]) {
        [self.webView stopLoading];//fire in didFailLoadWithError
    }
}

- (void)webViewDidStartLoad:(UIWebView *)webView{
    self.timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(timeout) userInfo:nil repeats:NO];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView{
    [self.timer invalidate];
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error{
    //Error 999 fire when stopLoading
    [self.timer invalidate];//invalidate for other errors, not time out. 
}

1 Comment

This is the better answer since it actually stops the web view after the timeout. I would also suggest setting self.timer to nil after you invalidate it and after it completes.
3

Swift coders can do it as follow:

var timeOut: NSTimer!

   func webViewDidStartLoad(webView: UIWebView) {
    self.timeOut = Timer.scheduledTimer(timeInterval: 7.0, target: self, selector: Selector(("cancelWeb")), userInfo: nil, repeats: false)
}

func webViewDidFinishLoad(webView: UIWebView) {
    self.timeOut.invalidate()
}

func webView(webView: UIWebView, didFailLoadWithError error: NSError?) {
    self.timeOut.invalidate()
}

func cancelWeb() {
    print("cancelWeb")
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.