Changing functionality

Closures also give us the ability to change the functionality of types on the fly. We saw, in Chapter 11, Working with Generics, that generics give us the ability to write functions that are valid for multiple types. With closures, we are able to write functions and types whose functionality can change, based on the closure that is passed in. In this section, we will show how to write a function whose functionality can be changed with a closure.

Let's begin by defining a type that will be used to demonstrate how to swap out functionality. We will name this type TestType:

struct TestType { 
  typealias getNumClosure = ((Int, Int) -> Int) 
 
  var numOne = 5 
  var numTwo = 8 
 
  var results = 0; 
 
  mutating func getNum(handler: getNumClosure) -> Int { 
    results = handler(numOne,numTwo) 
    print("Results: (results)") 
    return results 
  } 
} 

We begin this type by defining a typealias for our closure that is named getNumClosure. Any closure that is defined as a getNumClosure closure will take two integers and return a single integer. Within this closure, we assume that it does something with the integers that we pass in to get the value to return, but it really doesn't have to. To be honest, this class doesn't really care what the closure does as long as it conforms to the getNumClosure type. Next, we define three integers named numOne, numTwo, and results.

We also define a method named getNum(). This method accepts a closure that conforms to the getNumClosure type as its only parameter. Within the getNum() method, we execute the closure by passing in the numOne and numTwo variables, and the integer that is returned is put into the results class variable.

Now let's look at several closures that conform to the getNumClosure type that we can use with the getNum() method:

var max: TestType.getNumClosure = {  
  if $0 > $1 { 
    return $0 
  } else {  
  return $1 
  } 
} 
 
var min: TestType.getNumClosure = {  
  if $0 < $1 { 
    return $0 
  } else {  
    return $1 
  } 
} 
 
var multiply: TestType.getNumClosure = {  
  return $0 * $1 
} 
 
var second: TestType.getNumClosure = {  
  return $1 
} 
 
var answer: TestType.getNumClosure = {  
  var tmp = $0 + $1 
  return 42 
} 

In this code, we define five closures that conform to the getNumClosure type:

  • max: This returns the maximum value of the two integers that are passed
  • in min: This returns the minimum value of the two integers that are passed
  • in multiply: This multiplies both the values that are passed in and returns the product
  • second: This returns the second parameter that was passed in
  • answer: This returns the answer to life, the universe, and everything

In the answer closure, we have an extra line that looks like it does not have a purpose: _= $0 + $1. We do this purposely because the following code is not valid:

var answer: TestClass.getNumClosure = {  
  return 42 
} 

This type gives us the error: contextual type for closure argument list expects 2 arguments, which cannot be implicitly ignored. As we can see by the error, Swift will not let us ignore the expected parameters within the body of the closure. In the closure named second, Swift assumes that there are two parameters because $1 specifies the second parameter.

We can now pass each one of these closures to the getNum() method to change the functionality of the function to suit our needs. The following code illustrates this:

var myType = TestType() 
 
myType.getNum(handler: max)  
myType.getNum(handler: min) 
myType.getNum(handler: multiply)  
myType.getNum(handler: second)  
myType.getNum(handler: answer) 

When this code is run, we will receive the following results for each of the closures:

For Max:       Results: 8 
For Min:       Results: 5 
For Multiply:  Results: 40 
For Second:    Results: 8 
For Answer:    Results: 42 

The last example we are going to show you in this chapter is one that is used a lot in frameworks, especially ones that have a functionality that is designed to be run asynchronously.

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

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