In our day-to-day application development, we might need to develop some functions that return Optionals
. For instance, suppose that we need to read a file and return the content of that file. Using optionals, we can develop it as follows:
func checkForPath(path: String) -> String? { // check for the path return "path" } func readFile(path: String) -> String? { if let restult = checkForPath(path: path) { return restult } else { return nil } }
Here, checkForPath
is an incomplete function that checks for file existence.
When we call the readFile
function, we will need to check for the resulting optional:
if let result = readFile(path: "path/to") { // Do something with result }
Instead of using optionals in this scenario, we can use error handling to redirect the flow of control to eliminate errors and provide recoveries:
enum Result: ErrorProtocol { case failure case success } func readFile(path: String) throws -> String { if let restult = checkForPath(path: path) { return restult } else { throw Result.failure } }
When we call this function, we will need to wrap it inside a do
block and catch
the exception
:
do { let result = try readFile(path: "path/to") } catch { print(error) }
We can use try!
if we know that there is no way a method call will fail, or if it fails then our code will be broken and we should crash the application.
When we use the try!
keyword, we do not need to have do
and catch
around our code block because we promise it will never fail! It is a big promise that we should avoid.
In case we have to bypass error handling such as checking whether a database file exists, we can do the following:
do { let result = try readFile(path: "path/to") } catch { print(error) }
We can use try?
to handle an error by converting it to an Optional
value.
If an error is thrown while evaluating the try?
expression, the value of the expression is going to be nil
. For instance, in the following example, the result is going to be nil
if we cannot read the file:
let result = try? readFile(path: "path/to")