Since Result
has been introduced in Swift standard library, the way we normally passed errors has changed, especially while calling asynchronous APIs the completion handlers are more readable.
With Result
it’s easy to handle the value, as the value is binary, just like using a boolean value.
Let’s dive in with examples, and see how to use Result
in our code?
Let’s Start
// Declaration in Swift Library
@frozen enum Result<Success, Failure> where Failure : Error
Result
is very easy to use, and it is having two cases for our use, Success
and Failure
, both of them can hold values using generics, which means you can choose the type of values, but the value of Failure
must conform to Error
type. Generics makes our code powerful if used in the right way.
Let’s take an example.
enum APICallError: Error {
case error(title: String, message: String)
}
Above is the Error
type I use
Whenever my API gives an error, I need to show an alert to the user with title
and message
. And if all goes well, I’ll return a Dictionary
received from the API. Let’s see how we can do this.
// Result<[String: Any], APICallError>
func getListForUser(_ user: String, completion: @escaping (Result<[String: Any], APICallError>) -> ())
Here, in the Result
, the first type [String:Any]
is used in case the API was successful, and the second type APICallError
is used in case there was a failure. How do we use them?
func getListForUser(_ user: String, completion: @escaping (Result<[String: Any], APICallError>) -> ()) {
// Calling API and getting the result...
// In case of Success
completion(.success(jsonDict))
// In case of Failure
completion(.failure(APICallError.error(title: "Network Error", message: "Something went wrong, Please try again later")))
}
It is as easy as defined above in the code. If there’s a Success, simply use .success()
, and if there’s a Failure, use .failure()
.
How do we handle the Result
?
self.getListForUser(user) { result in
// Use Switch
switch result {
case .success(let dictionary):
// Do some work
case .failure(let error):
switch error {
case let .error(title: title, message: message):
// Show Alert
}
}
}
Using switch is one of the most common ways of handling the Result
, code is more readable and structured here.
Note: You can add more cases to APICallError
, and handle them inside the other switch declared in the failure case.
There are few more way of handling the Result
.
// E.g. 1
if case .success(let dictionary) = result {
// Use Dictionary
}
if case .error(let error) = result {
// Handle error
}
// E.g. 2
do {
if let dictionary = try result.get() {
// Use Dictionary
}
}catch {
// Handle error
}
Use if case .success(let dictionary) = result
to retrieve the dictionary
from the result
without handling the error
, or add another if statement to handle the error
.
Or try the old way of handling the errors by using Do-Catch
with the help of get()
function provided in Result,
which gives the success value if available or throws an error.
Result
is now widely used by many third-party SDKs. Start using Result
, it helps you improve your code readability and structure.
I hope you guys enjoyed reading my article. There’s a lot more to learn together, so subscribe to stay updated about my upcoming articles.
If you have any suggestions or questions, Feel free to connect me on Twitter or Reddit. 😉