If what you write is a set of functions that perform the same sequence of transformations, for example, when processing the result returned by the REST call (checking the response is not zero, checking the status, checking for application / server error, parsing response, and etc.), I would do it by creating a pipeline that converts input data at each step, and in the end returns either nil or a converted result of a certain type.
I chose the user operator >>> , which visually displays the data stream, but, of course, feel free to choose your own:
infix operator >>> { associativity left } func >>> <T, V> (params: T?, next: T -> V?) -> V? { if let params = params { return next(params) } return nil }
An operator is a function that receives a value of a certain type and a closure that converts a value to a value of another type as an input value. If the value is not nil, the function calls a closure, passing in the value and returning the return value. If the value is nil , then the operator returns nil .
Perhaps an example is needed, so suppose I have an array of integers, and I want to perform the following operations sequentially:
- sum all array elements
- calculate power 2
- divide by 5 and return the integer part and the remainder
- add the above 2 numbers together
These are 4 functions:
func sumArray(array: [Int]?) -> Int? { if let array = array { return array.reduce(0, combine: +) } return nil } func powerOf2(num: Int?) -> Int? { if let num = num { return num * num } return nil } func module5(num: Int?) -> (Int, Int)? { if let num = num { return (num / 5, num % 5) } return nil } func sum(params: (num1: Int, num2: Int)?) -> Int? { if let params = params { return params.num1 + params.num2 } return nil }
and thatβs how I will use:
let res: Int? = [1, 2, 3] >>> sumArray >>> powerOf2 >>> module5 >>> sum
The result of this expression is either nil or a type value, as defined in the last pipeline function, which in the example above is Int .
If you need to improve error handling, you can define an enumeration as follows:
enum Result<T> { case Value(T) case Error(MyErrorType) }
and replace all options in the above functions with Result<T> , returning Result.Error() instead of nil .