Result’s convenience APIs
Basics article available: The Result TypeThe Swift standard library’s Result
type might just be a simple enum with cases for modeling an operation’s success
or failure
, but it also comes with several really useful convenience APIs built-in.
For example, it has a closure-based initializer, which we can use to easily convert any expression that throws
into a Result
value:
let data: Data = ...
let decoder = JSONDecoder()
// This will create a Result<Model, Error> instance, which will contain
// 'success' if its expression succeeded, and 'failure' if it ended
// up throwing an error:
let result = Result {
try decoder.decode(Model.self, from: data)
}
// The above API is really useful when we want to return a Result
// value from an asynchronous operation, for example by calling
// a completion handler:
completionHandler(result)
Above we’re converting a raw Data
value into a decoded Result
, but we can also do the opposite — and extract a Data
value from a Result
instance, which we’ll then decode:
func decode(_ result: Result<Data, Error>) throws -> Model {
// Using Result's 'get' method, we can either extract its
// underlying value, or throw any error that it contains:
let data = try result.get()
let decoder = JSONDecoder()
return try decoder.decode(Model.self, from: data)
}
Finally, Result
also ships with a series of really useful mapping functions, for example map
— which enables us to convert any result’s value into a new type, without having to do any error handling as part of such an operation:
let dataResult: Result<Data, Error> = ...
let stringResult = dataResult.map {
String(decoding: $0, as: UTF8.self)
}