How to catch WebKit Errors - ios

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)")
}

Related

Firebase storage imageReference.delete{ (error) in } method crashing my app with "signal SIGABRT"

I'm using:
iOS - Swift 4
Cocoapods 1.4.0
Firebase (5.4.0)
FirebaseCore (5.0.5)
FirebaseStorage (3.0.0)
When I'm running the attached code, my app crashing with signal SIGABRT error at the AppDelegate class and prints libc++abi.dylib: terminating with uncaught exception of type NSException in the console.
I'v tried to run some debugging and what I found is that the problem occurred in the imageReference.delete{ (error) in } method.
*Note that it didn't enter to the block at all, it failed in the method itself and because of that the image is not deleting from Firebase console when I'm calling to the delete method.
My code:
func deleteImage(for url:String){
print(url) // https://firebasestorage.googleapis.com/v0/b/my-app.appspot.com/o/itemsImages%2F225121501531684886976.jpg?alt=media&token=token
let imageReference = Storage.storage().reference(forURL: url)
imageReference.delete { (error) in // Fails here with: libc++abi.dylib: terminating with uncaught exception of type NSException
print("completion") // Not getting to this point
if let error = error{
print(error)
}
}
}
Edit:
After very deep digging I'v understand that my problem is that I'm calling this method via closure at some point of the "events' tree" (I'm calling some function that calling to another function that calling to the delete method from closure) and thats what cause the problem.
Now the question is how can I call it via this closure without make this error? (I can't call it outside of it)
I'd start by asking if you have a strong reference to that image somewhere else ?
Or is the image being used in a UIImage Control?
At the end the problem was with the UITableView itself and not with Firebase.
I didn't update the UITableView's data array correctly and that produced this crashing. I wasn't aware of it because the errors in xCode's console were disabled from some reason (Those answeres helped me to enable it back: #1, #2).
Hope anyone else that will face with wired error like that (without enabled error logs, of course) will be able to use my unpleasant experience and find the solution faster and easier.

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.

Swift 2.1 do-try-catch not catching error

Here's my Swift 2.1 code snippet. The error that's occurring is shown in the comments at the point where the error appears.
The error shows up in the debugging panel, and the app crashes. The app never prints the line in the catch, nor does it gracefully return as expected.
let audioFileURL = receivedAudio.filePathURL
guard let audioFile = try? AVAudioFile(forReading: audioFileURL) else {
print("file setup failed")
return
}
let audioFileFrameCount = AVAudioFrameCount(audioFile.length)
audioFileBuffer = AVAudioPCMBuffer(PCMFormat: audioFile.fileFormat, frameCapacity: audioFileFrameCount)
do {
// ERROR: AVAudioFile.mm:263: -[AVAudioFile readIntoBuffer:frameCount:error:]: error -50
// Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'error -50'
// -50 = Core Audio: bad param
try audioFile.readIntoBuffer(audioFileBuffer)
}
catch {
print("unable to load sound file into buffer")
return
}
From everything I've seen, my do/try/catch format should be correct.
audioFile.readIntoBuffer returns void and has the keyword throws.
Yet, the catch is never executed.
What am I missing?
UPDATE: From Apple's documentation on AVAudioFile
For:
func readIntoBuffer(_ buffer: AVAudioPCMBuffer) throws
Under Discussion:
HANDLING ERRORS IN SWIFT:
In Swift, this API is imported as an initializer and is marked with the throws keyword to indicate that it throws an error in cases of failure.
You call this method in a try expression and handle any errors in the catch clauses of a do statement, as described in Error Handling in The Swift Programming Language (Swift 2.1) and Error Handling in Using Swift with Cocoa and Objective-C (Swift 2.1).
From The Swift Programming Language (Swift 2.1): Error Handline
NOTE
Error handling in Swift resembles exception handling in other languages, with the use of the try, catch and throw keywords. Unlike exception handling in many languages—including Objective-C—error handling in Swift does not involve unwinding the call stack, a process that can be computationally expensive. As such, the performance characteristics of a throw statement are comparable to those of a return statement.
And, finally, from the same document:
Handling Errors Using Do-Catch
You use a do-catch statement to handle errors by running a block of code. If an error is thrown by the code in the do clause, it is matched against the catch clauses to determine which one of them can handle the error.
I don't have to write and throw my own errors/exceptions for them to be caught. I should be able to catch Swift's exceptions as well.
The do - catch combination is fine. This issue is simply one that cannot be caught - and therefore never makes it to the catch block.
If the issue were catchable (defined and handled via Swift's throws functionality), the catch block would've been executed.
Some semantics: there is a long-standing argument about the differences between the terms error and exception.
Some developers consider the two terms to be distinct. In this case, the term error represents an issue that was designed to be handled. Swift's throws action would fit here. In this case, a do - catch combination would allow the issue to be caught.
An exception, for these developers, represents an unexpected, usually fatal, issue that cannot be caught and handled. (Generally, even if you could catch it, you would not be able to handle it.)
Others consider the two terms to be equivalent and interchangeable, regardless of whether the issue in question can be caught or not. (Apple's documentation seems to follow this philosophy.)
(Updated to focus on the answer rather than the semantics.)
catch will only catch the errors that are explicitly thrown. It will never catch exceptions.
What you seem to have here is an exception happening in the AVAudioFile SDK, not a Swift error, so it's not caught:
ERROR: AVAudioFile.mm:263: -[AVAudioFile readIntoBuffer:frameCount:error:]: error -50
Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'error -50'
-50 = Core Audio: bad param
In the context of Swift, "error" means an error thrown by a function, nothing else. The function being yours or not does not matter.
Exceptions in Swift are not caught ever. It's not the same as in Java at all, for example. In Swift, error != exception, they are two very different things.
I understand your opinion that "It should work for both" but it's simply not the case. You can see this as a semantic situation with using the keyword "catch" if you want, because it's the same keyword as other languages but behaves very differently; it resembles, but it's not the same.
As for your exception with AVAudioFile, I don't have a solution - maybe it's a bug in this SDK? Or it's not yet properly bind to Swift and the throwing system. In this case, and if nobody else has a solution, don't hesitate to report the bug to Apple.
see this example
struct E: ErrorType{}
func foo(i: Int) throws {
if i == 0 {
throw E()
}
print(10 / (i - 1))
}
do {
//try foo(1) // if you uncomment this line, the execution
// will crash, even though the function is declared
// as throwing and you use proper calling style (do / try / catch pattern)
try foo(0)
} catch {
print("error: ", error) // error: E()
}

UIWebView - what NSError's are thrown?

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);
}

UIWebView acting differently than Safari app

I'm working on an iOS app with an UIWebView. The webpage displayed in the UIWebView is working fine when displayed in the Safari app on iOS, but when it is displayed inside an UIWebView nothing happens when tapping the "Sign in" button: http://www.bnpsolutions.com/Common/Login_Mobile.aspx.
Does someone know why?
You can download my small iOS example project here:
http://uploads.demaweb.dk/WebView.zip
EDIT1:
I've changed the WebView to display a simple page which just including jQuery: http://uploads.demaweb.dk/WebView2.zip.
The error message is:
WebView[13623:11703] JavaScript exception: (/ajax/libs/jquery/1.7.2/jquery.js):5187 - SYNTAX_ERR - SYNTAX_ERR: DOM Exception 12
Line:
(function(){
Why are the UIWebView not able to load jQuery?
Well, using this code to debug your UIWebView i found 2 exceptions in your javascript related to the resource /WebResource.axd. Check that and I hope it result useful.
I would suggest defining the delegate methods:
– webView:shouldStartLoadWithRequest:navigationType:
– webViewDidStartLoad:
– webViewDidFinishLoad:
– webView:didFailLoadWithError: /* especially this one!! */
and put some NSLog traces there so that you can see what is happening. It is possible that Safari is more resilient to errors (or handles it in a friendlier way) than UIWebView, hence the difference in behavior. But you should check it directly in your app...
With regards to the error message generated - the UIWebView is indeed able to load jQuery - the message you're getting about the exception (based on the link in the comments about how debugging the UIWebView is hooked up) occurs when the exception is raised - whether the exception is caught or not.
That particular function in jQuery has a try/catch near the beginning of the function that purposefully tries to raise an exception (and catch it).
Try this code to see what I mean:
NSString *htmlString = #"<html><body>Hello World I am a <b>browser</b><script>(function(){try {var a=undefined; a();} catch (err) {} }());</script></body></html>";
[uiWebView loadHTMLString:htmlString baseURL:nil];
Whether the try/catch is there or not, the exception will be reported.

Resources