UIWebView - what NSError's are thrown? - ios

I'm trying to throw up an alert to users when a UIWebView fails to load a page because it can't reach the server. I'm using the delegate method:
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
// show NSAlert telling user there was a problem
}
(docs: https://developer.apple.com/library/ios/documentation/uikit/reference/UIWebViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UIWebViewDelegate/webView:didFailLoadWithError:)
The problem is that this method is called for other things as well - such as when you visit another page before the previous one has finished loading, etc. What specific NSError's should I check for for throwing my NSAlert? What NSError's does UIWebView throw? I can't see this documented anywhere!
Thanks.

If anyone does come up across the same problem, the solution ended up been to:
NSLog the error code and description every time the error function was called.
Do some stuff in my app that would generate errors
Watch the output to establish which codes corresponded to which actions (the error descriptions helped).
This is achieved simply by:
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
NSLog(#"%d", error.code);
NSLog(error.localizedDescription);
}

Related

How do I properly implement didFailProvisionalNavigation with WKWebView?

I'm making a web browser and like every other web browser I'd like to inform the user of the error that occurred when a web page failed to load.
Currently, I'm displaying the localizedDescription of the error in the didFailProvisionalNavigation method. That's all!
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
[self presentError:error.localizedDescription animated:YES];
[_delegate webViewDidFailNavigation:self error:error];
}
The presentError method handles some custom UI stuff irrelevant to the question.
The method above works excellent for displaying the usual errors such as:
The internet connection appears to be offline.
A server with the specified hostname could not be found.
But it also displays some unusual errors such as:
The operation could not be completed(NSURL ErrorDomain error -999)
I don't like this method for two reasons:
The error message displays some technical stuff "NSURL" but I could ignore that.
Most importantly most of the time when the error above is being displayed the web page is perfectly usable but since it's a didFailProvisionalNavigation error I have to disable the page from being used and instead present the error.
I'm not aware of what other minor errors could occur that shouldn't be handled the way I'm handling them. Unfortunately, I don't know of a way to distinguish between major errors such as "Connection appears to be offline" and minor errors such as "Operation couldn't be completed".
What is the standard way of handling navigation failures?
I needed to use didFailProvisionalNavigation too. For now I solved it like this:
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(nonnull NSError *)error
{
if(error.code != -999) // Prevent the error from showing when didFailProvisionalNavigation is triggered after a cancelled load (reload)
{
// Show the error
}
}
Instead of
webView(_:didFailProvisionalNavigation:withError:)
why do you not use this?
webView(_:didFail:withError:)
It seems that should only be called when there is an error preventing the site from displaying content, not when a page is already rendered and trying to load the next page.

When does the navigationDelegate in a WKWebView gets called if an error occurs?

Assume you are browsing the New York Times home page and you click a link to read an article before the page fully loads. The navigationDelegate get's called:
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error;
The error is:
"The operation couldn’t be completed."
As we normally expect the new page (that contains the article) should start loading after the error is thrown. In fact, I have logged this and I observed that the article page starts loading before the error is thrown, at exactly the time you click the article's title.
What I'm trying to do is to get the article URL and the solution I came up with is to store the last URL that the webView starts loading and when the navigationDelegate get's called to report the error use the lastURL as the new page URL.
When this method get's called:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
Store the URL here:
#property(nonatomic, retain) NSURL *lastURL;
What I'm afraid of is if the navigationDelegate get's called after a few more sub frames of the new web page are loaded, that will mess up the lastURL entirely. It will not have stored the article's true URL but some other URL that is part of the article.
So, when exactly does the navigationDelegate get's called to report the error? Can someone reassure me that my fears won't come true?

Connection Error Occurs When Browsing Too Fast

In the app that I'm writing, I check to see if the device has an internet connection. I put a connection error image over the screen, and hide it unless the device is not connected. There is an odd issue though. I implemented a simple back button for the UIWebView, but when I press it too fast, the connection error occurs. Here is the code I use to check for connection, and decide whether to display the error:
-(void)webView:(UIWebView *)myWebView didFailLoadWithError:(NSError *)error {
_connectionError.hidden = NO;
}
So, I think the only way to solve this issue would be to have it check if there is a connection one time, only when the app first launches, and never run again for the remainder of the time. I'm extremely new to Objective-C, and have no idea how to do this. I'm thinking that I should put something in viewDidLoad, or implement some way to have the method run only once, but I have no idea how to do that.
Here's the code for the back button:
- (IBAction)backButtonTapped:(id)sender {
[_viewWeb goBack];
}
Call the method stopLoading on the webView before the goBack method to make sure there is no multiple request going which can cause the connection error:
- (IBAction)backButtonTapped:(id)sender {
[_viewWeb stopLoading];
[_viewWeb goBack];
}
To check for a connection you can use Reachability in your project. You can then use this answer to see how to use it. This would be more efficient and cleaner than using a UIWebview.

RestKit: requeue RKRequest in RKRequestQueue

I'm trying to implement an upload queue in my application. I'm putting my RKRequests into RKRequestQueue and call [queue start]. But, as we all know, network connection is something that is not lasts forever. I'm using RKReachabilityObserver now to determine when to suspend and resume my queue, and it is working fine (at least now, however I've heard about some issues with reachability code in RestKit). This lets me to stop sending new data until network is available again. But when network connection is lost, all active RKRequests are issuing - (void)request:(RKRequest *)request didFailLoadWithError:(NSError *)error where, I thought, I will be able to put my RKRequest back in queue again.
So, I tried this:
- (void)request:(RKRequest *)request didFailLoadWithError:(NSError *)error
{
NSLog(#"Request failed");
[[request queue] cancelRequest:request];
[[request queue] addRequest:request];
}
but I'm getting an EXC_BAD_ACCESS somewhere in didFailLoadWithError method of RKRequest.
My question is: how can I requeue a RKRequest?
Instead of cancelling and adding to queue, do:
[request send];
But the best solution for this would really be to use RKClient, it makes things easier. You would not have to worry about queue. The client comes with and instance of RKRequestQueue and does all the magic behind the scenes, specifically it adds all requests configured for the given client to the clients request queue and dispatches them for you.

How to catch WebKit Errors

I wonder how i can catch and handle WebKit Errors in my iPad App. I found no information about ErrorDomain and ErrorCodes up till now. Is this a miracle?
This is what i see from time to time at the console in Xcode during testing on device (iPad2, iOS 5.0.1).
WebKit discarded an uncaught exception in the webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame: delegate: <(null)> A route has already been registered for class 'Publication' and HTTP method 'ANY'
How can i catch WebKit Errors? This Error raises during an alert(); in JS within the HTML Page that's loaded in a UIWebView.
I am not sure but maybe the:
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
could put some light on that issue (that's UIWebViewDelegate). Set the delegate and implement this method. Print the error description to the console and check it.
Here is a Swift 3 version of RaffAl's answer.
func webView(webView: UIWebView, didFailLoadWithError error: NSError) {
print("An error occurred!: \(error)")
}

Resources