Guarantee that no error is thrown in Swift 3 do-catch? - ios

If I have an asynchronous function that throws an error, how can I make sure no error is thrown before some more functions are executed?
do {
try foo()
} catch {
print("error: \(error)")
}
// HOW TO KNOW IF THE CALL WAS SUCCESSFUL HERE
I can have a variable that I change if an error is thrown, but it may be changed in some time if the call is asynchronous. I need to find a way to pause until foo() stops executing so I can be sure no error is thrown.

Related

throw Exception('oops!') vs throw 'oops!'

I notices some code that made me think the Exception function call was optional? E.g., do these two lines perform the same function?
throw Exception('oops!');
throw 'oops!'
No.
The former, throw Exception('oops!');, creates a new Exception object using the Exception constructor, then throws that object.
It can be caught by try { ... } on Exception catch (e) { ... }.
The latter, throw 'oops!'; throws the string object.
It can be caught by try { ... } on String catch (e) { ... }.
Generally, you shouldn't be doing either.
If someone made an error, something that would have been nice to catch at compile-time and reject the program, but which happens to not be that easy to detect, throw an Error (preferably some suitable subclass of Error).
Errors are not intended to be caught, but to make the program fail visibly. Some frameworks do catch errors and log them instead. They're typically able to restart the code which failed and carry on, without needing to understand why.
If your code hit some exceptional situation which the caller should be made aware of (and which prevents just continuing), throw a specific subclass of Exception, one which contains the information the caller needs to programmatically handle that situation. Document that the code throws this particular exception. It's really a different kind of return value more than it's an error report. Exceptions are intended to be caught and handled. Not handling an exception is, itself, an error (which is why it's OK for an uncaught exception to also make the program fail visibly).
If you're debugging, by all means throw "WAT!"; all you want. Just remove it before you release the code.

Difference between 'catch(e)' and 'on Exception catch(e)' in dart?

What is the difference between catch(e) and on Exception catch(e) in dart?
AVOID catches without on clauses.
Using catch clauses without on clauses makes your code prone to encountering unexpected errors that won't be thrown (and thus will go unnoticed).
BAD:
try {
somethingRisky()
} catch(e) {
doSomething(e);
}
GOOD:
try {
somethingRisky()
} on Exception catch(e) {
doSomething(e);
}
Link: avoid_catches_without_on_clauses
The } on Exception catch (e) { will catch all thrown objects implementing Exception.
The excludes most errors (which implement Error),
The } catch (e) { will catch all thrown objects, both exceptions and errors - and anything else that might get thrown. Most thrown objects implement either Exception or Error, but that's just a convention. Any non-null object can be thrown.
I'd actually recommend against on Exception as well. Exceptions are not errors, they are intended for functions as an alternative to returning a value, but exceptions are still just as much part of the function API, and you should only be catching the exceptions that you are actually planning to handle. Since Exception itself has no information, you should be catching the subtype that the function is documented as throwing so you can use the available information to handle the exceptional case.
If you are not going to handle it, you might as well treat the exception as an error.
Using only } catch (e) { to catch everything is reasonable in some situations, mainly in framework code which wraps other user code, and needs to make sure a user code error or unhandled exception doesn't take down the entire program.

Uncaught exception in appdelegate swift 3

How do I handle all unhandled exceptions in application level?
I tried with NSSetUncaughtExceptionHandler and it called only for NSExceptions.
I would like to handle uncaught exceptions in app level and allow users to continue with app without any crashes by navigating to home (some)page.
I recommend you to use try catch block in your code. It will help to prevent the crashes in your application.
do {
try {
// do something here
// if the call fails, the catch block is executed
}
} catch {
//do something when catch block executes.
}

startVPNTunnel not throws errors

I'm calling startVPNTunnel() and then in the PacketTunnelProvider class, I execute the completionBlock with an error.
The call to startVPNTunnel() is inside a try-catch block, but it's seems that there is nothing to catch.
I just want to alert the user if the connection succeeded or not.
Anyone else was able to catch those errors?
The relevant code is very simple:
do {
try vpnManager!.connection.startVPNTunnel()
}
catch {
NSLog("roee: Failed to start vpn: \(error)")
}
And inside PacketTunnelProvider:
let error = NSError(domain: NEVPNErrorDomain, code: NEVPNError.ConfigurationInvalid.rawValue, userInfo: nil)
PacketTunnelProvider.pendingStartCompletionHandler!(error)
PacketTunnelProvider.pendingStartCompletionHandler = nil
I believe startVPNTunnel talks to OS and let it knows that VPN needs to be started.
OS will do couple of checks around VPN configuration and will immediately return positive result (if configuration is fine) or error (if something is wrong). And if an error is returned then this API will throw.
However, your Network extension will be started after startVPNTunnel returned.
So you can't communicate like that.
You can register for NSNotification.Name.NEVPNStatusDidChange to see VPN status changes.

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

Resources