I do not know how do I handle runtime error in swift. I need to check for a parsing error and do something about it. Can anyone help me please?
I have code something like this:
var:SomeObject = parse("some string")
I need to handle any generic error that occurs in runtime.
Thanks!
If the function is yours, then in case of a failure, you can make that function return a nil value.
That way your line of code
var anObj:SomeObject = parse("some string")
would become something like this
var:SomeObject? = parse("some string")
Notice the ? sign. It means that the value in it is Optional. In simple words, it could be some actual value, or it could be nil.
After this function, you should perform a check like
If anObj != nil
{
//do something
}
else
{
//the parse didn't go right, handle the erorr here.
}
Swift 2 adds additional safety to your error checking. You use the throws keyword to specify which functions and methods could throw an error. Then you have the do, try, and catch keywords for when you call something that could throw:
// 1
enum ParseError: ErrorType {
case InvalidValue
}
// 2
func parseWithError(value:String) throws {
if value.count > 0 {
// yeaaa!
} else {
// 3
throw ParseError.InvalidValue
}
}
func parse(value:String) {
// 4
do {
try parseWithError(value)
} catch {
print("Could not parse! :[")
return
}
}
There are a few things to highlight here:
To create an error to throw, simply create an enum that derives from ErrorType.
You need to use the throws keyword to mark any function that can throw an error.
This throws an error, which will be caught in section 4.
Instead of try blocks, which might be familiar from other languages, you wrap any code that can throw an error in a do block. Then, you add the try keyword to each function call that could throw an error.
For more read here or this is the official documentation of Error Handling
Related
In my code I'm deserialising some XML using the SWXMLHash library. Its .value() method has the throws keyword in its declaration, as do any custom deserialise functions.
I have the following line of code:
let myValue : UInt8 = try? xml["Root"]["ValueNode"].value()
Since the library doesn't include a deserialiser for UInt8, I've defined my own:
extension UInt8: XMLElementDeserializable {
public static func deserialize(_ element: XMLElement) throws -> UInt8 {
return UInt8(element.text)!
}
}
This works when the node has a value. However, when the node doesn't exist or is nil, an error occurs on the following line:
return UInt8(element.text)! // Fatal error: Unexpectedly found nil while unwrapping an Optional value
This is supposed to happen, obviously. What I don't understand is why this error is not being caught by my try? statement and returning nil instead of throwing that error.
Can anyone help?
Not all errors can be caught in Swift. If you mark a function using the throws keyword it indicates that the function might throw a recoverable error. However, your custom implementation doesn't actually throw any errors. Only errors thrown from functions marked with the throws keyword and thrown using the code throw Error can be caught by a do-catch block.
try? is a way to convert a throwable function's return value to an optional. If the function would throw an error, the value after the try? will be nil, otherwise it will be an optional value.
When you use the !, you specifically tell the compiler that you know what you are doing and if the operation on which you used the ! fails, your app shouldn't fail gracefully.
You'll need to change your deserialize method to handle the optional unwrapping gracefully or throw and error.
extension UInt8: XMLElementDeserializable {
public static func deserialize(_ element: XMLElement) throws -> UInt8 {
if let val = UInt8(element.text) {
return val
} else {
throw NSError(domain: "Couldn't deserialize value to UInt8", code: 1)
}
}
}
return UInt8(element.text)!
There's no try in this line. Therefore, no errors are going to be thrown here. If UInt8 can't convert the string it's given, it just returns nil. And then, of course, your ! turns that nil into a crash.
Instead of that, do something like this instead:
guard let retVal = UInt8(element.text) else { throw SomeError }
return retVal
In general: When there's a way to do something using !, and another way to do the same thing without using !, go for the second one unless you've got a really good reason.
I come from a .NET background, where error handling can be as simple as wrapping a set of statements in a try-catch. For example:
try
{
statement1
statement2
}
catch (ex)
{
log(ex.Message)
}
I'm trying to add error handling in my Swift project, and all the articles I have read so far seem to indicate that error handling requires more work in Swift. In the example above, it seems I would need to know exactly which statement throws an error, and then add a "try" before it. Is it not possible to simply wrap a block of code in a try-catch, and inspect the error that gets thrown?
Nope, you can't just wrap a block of code with try-catch.
First of all, cause not every line of code could produce exceptions. Only functions marked as "throws" could produce exceptions.
For example, you have some function:
deserialise(json: JSON) -> MyObjectType throws
And let this functions throws exceptions of type MyErrorType
That's how you should use it:
....
do {
let deserialisedObject = try deserialise(jsonObject)
... // do whatever you want with deserialised object here
} catch let error as MyErrorType {
... // do whatever you want with error here
}
...
So, as you see, exceptions in swift is not the same thing as exceptions in C++(or other regular language) for .NET
You can use try catch in swift just like you do in .net with this little change in structure,
before that create a enum of exceptions which you want to catch like follows
//exceptions to catch, change as per your need
enum someActionError: Error {
case invalidSelection
case outOfStock
}
//use
do {
try statement1
} catch someActionError.invalidSelection {
print("Invalid Selection.")
} catch someActionError.outOfStock {
print("Out of Stock.")
}
When calling a function in Swift 3 that throws, you have to be exhaustive in catching all possible errors, which often means you have an unnecessary extra catch {} at the end to handle errors that won't happen.
Is it possible to say throws MyErrorType so that the compiler can know you have indeed been exhaustive when you handle all cases from that enumeration?
There's no simple way to be type-safe with thrown errors. Consider this, if the compiler allowed you to specify throws MyErrorType, then it would also have to ensure within that function body that you're not trying a function that could potentially throw a different type outside of a do/catch block. (Well there is but it would add layers of unnecessary complexity). The Swift compiler can already be slow and get stuck in loops when inferring types, inferring Thrown types all the way up a chain of throwing functions could be a nightmare.
The running idea is that for most errors you're going to handle them in a small subset of ways anyhow.
That being said, there's no need for you to add extra catch let error as MyErrorType clauses, you can simply use a switch in a catch block like so:
do {
try something()
} catch let e {
switch e {
case let m as MyErrorType: handleMyError(m)
case let o as OtherErrorType: handleOther(o)
case is ThirdErrorType: print("error \(e)")
default: handleElse(e)
}
}
My suggestion for this problem is instead of throwing an error return a Result type in your function. It would be something like this.
enum MyCustomError: Error {
case genericError
}
func operationThatFails() -> Result<Response, MyCustomError> {
guard requiredConsition() else {
return .failure(.genericError)
}
return Response()
}
Then you can handle the error like this:
let result = operationThatFails()
switch result {
case .success(let value):
// handle success
case .failure(let error):
// handle error
}
This way your error is always type safe
Coming from Android, wrapping a block of code in a try..catch statement is straightforward.
try{
//A whole lot of code
} catch (Exception e) {
//Exception is a parameter
}
I wanted to do the same thing in Swift, but it doesn't seem to be quite this easy.
If I understand correctly, you need place a try in front of something that you think will go wrong.
Is there anything similar to the Android - functionality I described in the Swift toolbox?
Error handling in Swift 2 takes two things into consideration:
Whether the method can throw an error (marked with throws keyword in its declaration).
Whether the method that can throw is called from throwing scope (e.g. another methods that can throw) or not.
For non-throwing methods it's simple: you do not need to put any try or do/catch.
Methods that throw must always be prefixed by try, regardless of scope. So, that's a part of the answer to your question.
In case if scope is throwing, you do not have to use do/catch (but you can). In this case all errors thrown in current scope that are not handled by it will be passed upstream to the parent throwing scope.
If the scope is non-throwing, then you must handle all errors that can possibly be thrown by the methods that are called from said scope. Therefore, you must use do/catch.
Depending on your particular case, you might have to put do/catch around as well. If your current scope is non-throwing you will have to.
There are 3 types of do/catch.
I. Catch all
do {
methodThadDoesNotThrow()
try methodThatThrows()
}
catch {
// This will catch all errors that can be possibly thrown.
// You get implicit local-scope variable `error` that holds thrown error.
}
II. Catch concrete error type
Errors that can be thrown must implement ErrorType protocol. This is the only pre-requisite. They do not really have to be NSError or its descendants (this type is just a legacy from Objective-C). Therefore, if you know the concrete error type that you expect you can do something like:
do {
methodThadDoesNotThrow()
try methodThatThrows()
}
catch let error as CustomErrorType {
// This will catch all `CustomErrorType` errors.
// You get explicit local-scope variable `error` of `CustomErrorType` type.
}
III. Catch concrete error instance
Typically error types are declared as enums. For example:
enum CustomErrorType {
case SomethingStrange(String)
case SomethingMildlyHorrible
case Apocalypse
}
If you want to catch some specific case of CustomErrorType, you can do:
do {
methodThadDoesNotThrow()
try methodThatThrows()
}
catch CustomErrorType.SomethingStrange(let message) {
// This will catch only `CustomErrorType.SomethingStrange` errors.
// You get explicit local-scope variable `message` that
// will come from the value associated with the error enum-case.
}
There is, of course, the case of:
IV. Combine all together
do {
methodThadDoesNotThrow()
try methodThatThrows()
}
catch CustomErrorType.SomethingStrange(let message) {
// This will catch `CustomErrorType.SomethingStrange` error.
}
catch let error as CustomErrorType {
// This will catch the rest of `CustomErrorType` errors.
}
catch {
// Finally, this will catch all the rest of the errors
// (anything that is not `CustomErrorType` in this case).
}
I'm writing a utility function which takes a parameter and always returns a valid non-nil result (notice the returned value is not optional because the possible parameters are all actually hardcoded and valid, so I know the function cannot fail):
func myFunction(param: String) -> NonTrivialObject {...}
Now, during development I want to experiment with possible parameters and, should I make a mistake, I want the function to throw an exception and just crash. I don't want or need to throw Swift errors or catch them, I want to hard-crash and fix the parameter immediately. In Objective C I would just use NSParameterAssert() or do something along these lines:
guard let validatedParam = param where param != nil else {
NSException(...).raise()
return nil
}
// do the actual work and return a non-optional result
However, I cannot return nil because the result is not an optional. Is there a way to somehow tell the compiler that it doesn't need to bother returning anything from the function after an exception is thrown? Or am I doomed to litter my code with unwrapping optionals or try! statements or to return a dummy object just to make the compiler pleased?
You can use Swift assert(_:_file:line:) function as follows
assert(some condition, "Message to display if condition is false (optional)" )
If the condition is verified the app will continue running, otherwise it will terminate
An optional may contain nil, but Swift syntax forces you to safely deal with it using the ? syntax to indicate to the compiler you understand the behavior and will handle it safely.
You can define the function to be a throwing function:
func foo(param: String) throws -> NonTrivialObject {
guard param != nil else {
throw SomeErrorEnum.NilFound
}
doStuff(...)
}
The error enum needs to conform to the ErrorType protocol. The function call is now able to catch errors like this:
do {
try foo(param)
} catch SomeErrorEnum.NilFound {
print("Found nil")
}
In this way the function returns a non-optional but can also throw errors. For more information see: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html