Selecting a closure based on results

In the final example, we will pass two closures to a method, and then, depending on some logic, one or possibly both of the closures will be executed. Generally, one of the closures is called if the method was successfully executed and the other closure is called if the method failed.

Let's start off by creating a type that will contain a method that will accept two closures and then execute one of the closures based on the defined logic. We will name this type TestType. Here is the code for the TestType type:

class TestType { 
  typealias ResultsClosure = ((String) -> Void) 
 
  func isGreater(numOne: Int, numTwo: Int, successHandler: ResultsClosure,
failureHandler: ResultsClosure) { if numOne > numTwo { successHandler("(numOne) is greater than (numTwo)") } else { failureHandler("(numOne) is not greater than (numTwo)") } } }

We begin this type by creating a typealias that defines the closure that we will use for both the successful and failure closures. We will name this typealias ResultsClosure. This example also illustrates why you should use a typealias rather than retyping the closure definition. It saves us a lot of typing and prevents us from making mistakes. In this example, if we did not use a typealias, we would need to retype the closure definition four times, and if we needed to change the closure definition, we would need to change it in four spots. With the type alias, we only need to type the closure definition once and then use the alias throughout the remaining code.

We then create a method named isGreater, which takes two integers as the first two parameters, and two closures as the next two parameters. The first closure is named successHandler, and the second closure is named failureHandler. Within this method, we check whether the first integer parameter is greater than the second one. If the first integer is greater, the successHandler closure is executed, otherwise, the failureHandler closure is executed.

Now, let's create two closures outside of the TestType structure. The code for these two closures is as follows:

var success: TestType.ResultsClosure = {  
  print("Success: ($0)") 
} 
 
var failure: TestType.ResultsClosure = {  
  print("Failure: ($0)") 
} 

Note that both closures are defined as the TestClass.ResultsClosure type. In each closure, we simply print a message to the console to let us know which closure was executed. Normally, we would put some functionality in the closure.

We will then call the method with both the closures, as follows:

var test = TestType() 
test.isGreater(numOne: 8, numTwo: 6, successHandler: success, failureHandler: failure) 

Note that in the method call, we are sending both the success closure and the failure closure. In this example, we will see the message Success: 8 is greater than 6. If we reversed the numbers, we would see the message Failure: 6 is not greater than 8. This use case is really good when we call asynchronous methods, such as loading data from a web service. If the web service call was successful, the success closure is called; otherwise, the failure closure is called.

One big advantage of using closures like this is that the UI does not freeze while we wait for the asynchronous call to complete. This also involves a concurrency piece, which we will be covering in Chapter 14, Concurrency and Parallelism in Swift, later in this book. As an example, if we tried to retrieve data from a web service as follows:

var data = myWebClass.myWebServiceCall(someParameter) 

Our UI would freeze while we wait for the response to come back, or we would have to make the call in a separate thread so that the UI would not hang. With closures, we pass the closures to the networking framework and rely on the framework to execute the appropriate closure when it is done. This does rely on the framework to implement concurrency correctly, to make the calls asynchronously, but a decent framework should handle that for us.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset